From: khartlage Date: Thu, 30 Jan 2003 19:45:33 +0000 (+0000) Subject: JDT codeassist module, nothing changed yet X-Git-Url: http://secure.phpeclipse.com JDT codeassist module, nothing changed yet --- diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java new file mode 100644 index 0000000..7422223 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java @@ -0,0 +1,109 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import java.util.EventObject; + +/** + * A buffer changed event describes how a buffer has changed. These events are + * used in IBufferChangedListener notifications. + *

+ * For text insertions, getOffset is the offset + * of the first inserted character, getText is the + * inserted text, and getLength is 0. + *

+ *

+ * For text removals, getOffset is the offset + * of the first removed character, getText is null, + * and getLength is the length of the text that was removed. + *

+ *

+ * For replacements (including IBuffer.setContents), + * getOffset is the offset + * of the first replaced character, getText is the replacement + * text, and getLength is the length of the original text + * that was replaced. + *

+ *

+ * When a buffer is closed, getOffset is 0, getLength + * is 0, and getText is null. + *

+ *

+ * This class is not intended to be instantiated or subclassed by clients. + * Instances of this class are automatically created by the Java model. + *

+ * + * @see IBuffer + */ +public class BufferChangedEvent extends EventObject { + + /** + * The length of text that has been modified in the buffer. + */ + private int length; + + /** + * The offset into the buffer where the modification took place. + */ + private int offset; + + /** + * The text that was modified. + */ + private String text; + +/** + * Creates a new buffer changed event indicating that the given buffer has changed. + */ +public BufferChangedEvent(IBuffer buffer, int offset, int length, String text) { + super(buffer); + this.offset = offset; + this.length = length; + this.text = text; +} +/** + * Returns the buffer which has changed. + * + * @return the buffer affected by the change + */ +public IBuffer getBuffer() { + return (IBuffer) source; +} +/** + * Returns the length of text removed or replaced in the buffer, or + * 0 if text has been inserted into the buffer. + * + * @return the length of the original text fragment modified by the + * buffer change ( 0 in case of insertion). + */ +public int getLength() { + return this.length; +} +/** + * Returns the index of the first character inserted, removed, or replaced + * in the buffer. + * + * @return the source offset of the textual manipulation in the buffer + */ +public int getOffset() { + return this.offset; +} +/** + * Returns the text that was inserted, the replacement text, + * or null if text has been removed. + * + * @return the text corresponding to the buffer change ( null + * in case of deletion). + */ +public String getText() { + return this.text; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java new file mode 100644 index 0000000..01660ae --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * A buffer contains the text contents of a resource. It is not language-specific. + * The contents may be in the process of being edited, differing from the actual contents of the + * underlying resource. A buffer has an owner, which is an IOpenable. + * If a buffer does not have an underlying resource, saving the buffer has no effect. + * Buffers can be read-only. + *

+ * Note that java model operations that manipulate an IBuffer (e.g. + * IType.createMethod(...)) ensures that the same line delimiter + * (i.e. either "\n" or "\r" or "\r\n") is + * used across the whole buffer. Thus these operations may change the line delimiter(s) + * included in the string to be append, or replaced. + * However implementers of this interface should be aware that other clients of IBuffer + * might not do such transformations beforehand. + *

+ * This interface may be implemented by clients. + *

+ */ +public interface IBuffer { + +/** + * Adds the given listener for changes to this buffer. + * Has no effect if an identical listener is already registered or if the buffer + * is closed. + * + * @param listener the listener of buffer changes + */ +public void addBufferChangedListener(IBufferChangedListener listener); +/** + * Appends the given character array to the contents of the buffer. + * This buffer will now have unsaved changes. + * Any client can append to the contents of the buffer, not just the owner of the buffer. + * Reports a buffer changed event. + *

+ * Has no effect if this buffer is read-only. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @param text the given character array to append to contents of the buffer + */ +public void append(char[] text); +/** + * Appends the given string to the contents of the buffer. + * This buffer will now have unsaved changes. + * Any client can append to the contents of the buffer, not just the owner of the buffer. + * Reports a buffer changed event. + *

+ * Has no effect if this buffer is read-only. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @param text the String to append to the contents of the buffer + */ +public void append(String text); +/** + * Closes the buffer. Any unsaved changes are lost. Reports a buffer changed event + * with a 0 offset and a 0 length. When this event is fired, the buffer should already + * be closed. + *

+ * Further operations on the buffer are not allowed, except for close. If an + * attempt is made to close an already closed buffer, the second attempt has no effect. + */ +public void close(); +/** + * Returns the character at the given position in this buffer. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @param position a zero-based source offset in this buffer + * @return the character at the given position in this buffer + */ +public char getChar(int position); +/** + * Returns the contents of this buffer as a character array, or null if + * the buffer has not been initialized. + *

+ * Callers should make no assumption about whether the returned character array + * is or is not the genuine article or a copy. In other words, if the client + * wishes to change this array, they should make a copy. Likewise, if the + * client wishes to hang on to the array in its current state, they should + * make a copy. + *

+ *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @return the characters contained in this buffer + */ +public char[] getCharacters(); +/** + * Returns the contents of this buffer as a String. Like all strings, + * the result is an immutable value object., It can also answer null if + * the buffer has not been initialized. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @return the contents of this buffer as a String + */ +public String getContents(); +/** + * Returns number of characters stored in this buffer. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @return the number of characters in this buffer + */ +public int getLength(); +/** + * Returns the Java openable element owning of this buffer. + * + * @return the openable element owning this buffer + */ +public IOpenable getOwner(); +/** + * Returns the given range of text in this buffer. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @param offset the zero-based starting offset + * @param length the number of characters to retrieve + * @return the given range of text in this buffer + */ +public String getText(int offset, int length); +/** + * Returns the underlying resource for which this buffer was opened, + * or null if this buffer was not opened on a resource. + * + * @return the underlying resource for this buffer, or null + * if none. + */ +public IResource getUnderlyingResource(); +/** + * Returns whether this buffer has been modified since it + * was opened or since it was last saved. + * If a buffer does not have an underlying resource, this method always + * returns true. + * + * @return a boolean indicating presence of unsaved changes (in + * the absence of any underlying resource, it will always return true). + */ +public boolean hasUnsavedChanges(); +/** + * Returns whether this buffer has been closed. + * + * @return a boolean indicating whether this buffer is closed. + */ +public boolean isClosed(); +/** + * Returns whether this buffer is read-only. + * + * @return a boolean indicating whether this buffer is read-only + */ +public boolean isReadOnly(); +/** + * Removes the given listener from this buffer. + * Has no affect if an identical listener is not registered or if the buffer is closed. + * + * @param listener the listener + */ +public void removeBufferChangedListener(IBufferChangedListener listener); +/** + * Replaces the given range of characters in this buffer with the given text. + * position and position + length must be in the range [0, getLength()]. + * length must not be negative. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @param position the zero-based starting position of the affected text range in this buffer + * @param length the length of the affected text range in this buffer + * @param text the replacing text as a character array + */ +public void replace(int position, int length, char[] text); +/** + * Replaces the given range of characters in this buffer with the given text. + * position and position + length must be in the range [0, getLength()]. + * length must not be negative. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @param position the zero-based starting position of the affected text range in this buffer + * @param length the length of the affected text range in this buffer + * @param text the replacing text as a String + */ +public void replace(int position, int length, String text); +/** + * Saves the contents of this buffer to its underlying resource. If + * successful, this buffer will have no unsaved changes. + * The buffer is left open. Saving a buffer with no unsaved + * changes has no effect - the underlying resource is not changed. + * If the buffer does not have an underlying resource or is read-only, this + * has no effect. + *

+ * The force parameter controls how this method deals with + * cases where the workbench is not completely in sync with the local file system. + * If false is specified, this method will only attempt + * to overwrite a corresponding file in the local file system provided + * it is in sync with the workbench. This option ensures there is no + * unintended data loss; it is the recommended setting. + * However, if true is specified, an attempt will be made + * to write a corresponding file in the local file system, + * overwriting any existing one if need be. + * In either case, if this method succeeds, the resource will be marked + * as being local (even if it wasn't before). + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @param progress the progress monitor to notify + * @param force a boolean flag indicating how to deal with resource + * inconsistencies. + * + * @exception JavaModelException if an error occurs writing the buffer + * to the underlying resource + * + * @see org.eclipse.core.resources.IFile#setContents(java.io.InputStream, boolean, boolean, org.eclipse.core.runtime.IProgressMonitor) + */ +public void save(IProgressMonitor progress, boolean force) throws JavaModelException; +/** + * Sets the contents of this buffer to the given character array. + * This buffer will now have unsaved changes. + * Any client can set the contents of the buffer, not just the owner of the buffer. + * Reports a buffer changed event. + *

+ * Equivalent to replace(0,getLength(),contents). + *

+ *

+ * Has no effect if this buffer is read-only. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @param contents the new contents of this buffer as a character array + */ +public void setContents(char[] contents); +/** + * Sets the contents of this buffer to the given String. + * This buffer will now have unsaved changes. + * Any client can set the contents of the buffer, not just the owner of the buffer. + * Reports a buffer changed event. + *

+ * Equivalent to replace(0,getLength(),contents). + *

+ *

+ * Has no effect if this buffer is read-only. + *

+ * A RuntimeException might be thrown if the buffer is closed. + * + * @param contents the new contents of this buffer as a String + */ +public void setContents(String contents); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java new file mode 100644 index 0000000..1cfe50d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * A listener, which gets notified when the contents of a specific buffer + * have changed, or when the buffer is closed. + * When a buffer is closed, the listener is notified after the buffer has been closed. + * A listener is not notified when a buffer is saved. + *

+ * This interface may be implemented by clients. + *

+ */ +public interface IBufferChangedListener { + + /** + * Notifies that the given event has occurred. + * + * @param event the change event + */ + public void bufferChanged(BufferChangedEvent event); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java new file mode 100644 index 0000000..38c45db --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * A factory that creates IBuffers for openables. + *

+ * This interface may be implemented by clients. + *

+ * @since 2.0 + */ +public interface IBufferFactory { + + /** + * Creates a buffer for the given owner. + * The new buffer will be initialized with the contents of the owner + * if and only if it was not already initialized by the factory (a buffer is uninitialized if + * its content is null). + * + * @param owner the owner of the buffer + * @see IBuffer + */ + IBuffer createBuffer(IOpenable owner); +} + diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeAssist.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeAssist.java new file mode 100644 index 0000000..5f3c04c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeAssist.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * Common protocol for Java elements that support source code assist and code + * resolve. + *

+ * This interface is not intended to be implemented by clients. + *

+ */ +public interface ICodeAssist { + + /** + * Performs code completion at the given offset position in this compilation unit, + * reporting results to the given completion requestor. The offset + * is the 0-based index of the character, after which code assist is desired. + * An offset of -1 indicates to code assist at the beginning of this + * compilation unit. + * + * @param offset the given offset position + * @param requestor the given completion requestor + * @exception JavaModelException if code assist could not be performed. Reasons include: + * + * @exception IllegalArgumentException if requestor is null + * @since 2.0 + * */ + void codeComplete(int offset, ICompletionRequestor requestor) + throws JavaModelException; + /** + * Performs code selection on the given selected text in this compilation unit, + * reporting results to the given selection requestor. The offset + * is the 0-based index of the first selected character. The length + * is the number of selected characters. + * + * @param offset the given offset position + * @param length the number of selected characters + * + * @exception JavaModelException if code resolve could not be performed. Reasons include: + *
  • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
  • + *
  • The range specified is not within this element's + * source range (INDEX_OUT_OF_BOUNDS) + * + * + */ + IJavaElement[] codeSelect(int offset, int length) throws JavaModelException; + + /** + * Performs code completion at the given offset position in this compilation unit, + * reporting results to the given completion requestor. The offset + * is the 0-based index of the character, after which code assist is desired. + * An offset of -1 indicates to code assist at the beginning of this + * compilation unit. + * + * @param offset the given offset position + * @param requestor the given completion requestor + * + * @exception JavaModelException if code assist could not be performed. Reasons include: + * + * @exception IllegalArgumentException if requestor is null + * @deprecated - use codeComplete(int, ICompletionRequestor) instead + */ +// void codeComplete(int offset, ICodeCompletionRequestor requestor) +// throws JavaModelException; +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeFormatter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeFormatter.java new file mode 100644 index 0000000..15d6dcb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICodeFormatter.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * Specification for a generic source code formatter. Client plug-ins can contribute + * an implementation for an ICodeFormatter, through the extension point "net.sourceforge.phpdt.core.codeFormatter". + * In case none is found, a default formatter can be provided through the ToolFactory. + * + * @see ToolFactory#createCodeFormatter() + * @see ToolFactory#createDefaultCodeFormatter(Map options) + * @since 2.0 + */ +public interface ICodeFormatter { + + /** + * Formats the String sourceString, + * and returns a string containing the formatted version. + * + * @param string the string to format + * @param indentationLevel the initial indentation level, used + * to shift left/right the entire source fragment. An initial indentation + * level of zero has no effect. + * @param positions an array of positions to map. These are + * character-based source positions inside the original source, + * for which corresponding positions in the formatted source will + * be computed (so as to relocate elements associated with the original + * source). It updates the positions array with updated positions. + * If set to null, then no positions are mapped. + * @param lineSeparator the line separator to use in formatted source, + * if set to null, then the platform default one will be used. + * @return the formatted output string. + */ + String format(String string, int indentationLevel, int[] positions, String lineSeparator); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICompilationUnit.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICompilationUnit.java new file mode 100644 index 0000000..4d44420 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICompilationUnit.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * Represents an entire Java compilation unit (.java source file). + * Compilation unit elements need to be opened before they can be navigated or manipulated. + * The children are of type IPackageDeclaration, + * IImportContainer, and IType, + * and appear in the order in which they are declared in the source. + * If a .java file cannot be parsed, its structure remains unknown. + * Use IJavaElement.isStructureKnown to determine whether this is + * the case. + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface ICompilationUnit extends IJavaElement, ISourceReference, IParent, IOpenable, IWorkingCopy, ISourceManipulation, ICodeAssist { +/** + * Creates and returns an import declaration in this compilation unit + * with the given name. + *

    + * Optionally, the new element can be positioned before the specified + * sibling. If no sibling is specified, the element will be inserted + * as the last import declaration in this compilation unit. + *

    + * If the compilation unit already includes the specified import declaration, + * the import is not generated (it does not generate duplicates). + * Note that it is valid to specify both a single-type import and an on-demand import + * for the same package, for example "java.io.File" and + * "java.io.*", in which case both are preserved since the semantics + * of this are not the same as just importing "java.io.*". + * Importing "java.lang.*", or the package in which the compilation unit + * is defined, are not treated as special cases. If they are specified, they are + * included in the result. + * + * @param name the name of the import declaration to add as defined by JLS2 7.5. (For example: "java.io.File" or + * "java.awt.*") + * @param sibling the existing element which the import declaration will be inserted immediately before (if + * null , then this import will be inserted as the last import declaration. + * @param monitor the progress monitor to notify + * @return the newly inserted import declaration (or the previously existing one in case attempting to create a duplicate) + * + * @exception JavaModelException if the element could not be created. Reasons include: + *

    + */ +//IImportDeclaration createImport(String name, IJavaElement sibling, IProgressMonitor monitor) throws JavaModelException; +/** + * Creates and returns a package declaration in this compilation unit + * with the given package name. + * + *

    If the compilation unit already includes the specified package declaration, + * it is not generated (it does not generate duplicates). + * + * @param name the name of the package declaration to add as defined by JLS2 7.4. (For example, "java.lang") + * @param monitor the progress monitor to notify + * @return the newly inserted package declaration (or the previously existing one in case attempting to create a duplicate) + * + * @exception JavaModelException if the element could not be created. Reasons include: + *

    + */ + //IPackageDeclaration createPackageDeclaration(String name, IProgressMonitor monitor) throws JavaModelException; +/** + * Creates and returns a type in this compilation unit with the + * given contents. If this compilation unit does not exist, one + * will be created with an appropriate package declaration. + *

    + * Optionally, the new type can be positioned before the specified + * sibling. If sibling is null, the type will be appended + * to the end of this compilation unit. + * + *

    It is possible that a type with the same name already exists in this compilation unit. + * The value of the force parameter effects the resolution of + * such a conflict:

    + * + * @param contents the source contents of the type declaration to add. + * @param sibling the existing element which the type will be inserted immediately before (if + * null , then this type will be inserted as the last type declaration. + * @param force a boolean flag indicating how to deal with duplicates + * @param monitor the progress monitor to notify + * @return the newly inserted type + * + * @exception JavaModelException if the element could not be created. Reasons include: + * + */ +IType createType(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws JavaModelException; +/** + * Returns all types declared in this compilation unit in the order + * in which they appear in the source. + * This includes all top-level types and nested member types. + * It does NOT include local types (types defined in methods). + * + * @return the array of top-level and member types defined in a compilation unit, in declaration order. + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +IType[] getAllTypes() throws JavaModelException; +/** + * Returns the smallest element within this compilation unit that + * includes the given source position (that is, a method, field, etc.), or + * null if there is no element other than the compilation + * unit itself at the given position, or if the given position is not + * within the source range of this compilation unit. + * + * @param position a source position inside the compilation unit + * @return the innermost Java element enclosing a given source position or null + * if none (excluding the compilation unit). + * @exception JavaModelException if the compilation unit does not exist or if an + * exception occurs while accessing its corresponding resource + */ +IJavaElement getElementAt(int position) throws JavaModelException; +/** + * Returns the first import declaration in this compilation unit with the given name. + * This is a handle-only method. The import declaration may or may not exist. This + * is a convenience method - imports can also be accessed from a compilation unit's + * import container. + * + * @param name the name of the import to find as defined by JLS2 7.5. (For example: "java.io.File" + * or "java.awt.*") + * @return a handle onto the corresponding import declaration. The import declaration may or may not exist. + */ +// IImportDeclaration getImport(String name) ; +/** + * Returns the import container for this compilation unit. + * This is a handle-only method. The import container may or + * may not exist. The import container can used to access the + * imports. + * @return a handle onto the corresponding import container. The + * import contain may or may not exist. + */ +// IImportContainer getImportContainer(); +/** + * Returns the import declarations in this compilation unit + * in the order in which they appear in the source. This is + * a convenience method - import declarations can also be + * accessed from a compilation unit's import container. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +// IImportDeclaration[] getImports() throws JavaModelException; +/** + * Returns the first package declaration in this compilation unit with the given package name + * (there normally is at most one package declaration). + * This is a handle-only method. The package declaration may or may not exist. + * + * @param name the name of the package declaration as defined by JLS2 7.4. (For example, "java.lang") + */ +// IPackageDeclaration getPackageDeclaration(String name); +/** + * Returns the package declarations in this compilation unit + * in the order in which they appear in the source. + * There normally is at most one package declaration. + * + * @return an array of package declaration (normally of size one) + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +// IPackageDeclaration[] getPackageDeclarations() throws JavaModelException; +/** + * Returns the top-level type declared in this compilation unit with the given simple type name. + * The type name has to be a valid compilation unit name. + * This is a handle-only method. The type may or may not exist. + * + * @param name the simple name of the requested type in the compilation unit + * @return a handle onto the corresponding type. The type may or may not exist. + * @see JavaConventions#validateCompilationUnitName(String name) + */ +IType getType(String name); +/** + * Returns the top-level types declared in this compilation unit + * in the order in which they appear in the source. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +IType[] getTypes() throws JavaModelException; + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICompletionRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICompletionRequestor.java new file mode 100644 index 0000000..4586a1d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ICompletionRequestor.java @@ -0,0 +1,405 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import net.sourceforge.phpdt.core.compiler.IProblem; + +/** + * A completion requestor accepts results as they are computed and is aware + * of source positions to complete the various different results. + *

    + * This interface may be implemented by clients. + *

    + * + * @see ICodeAssist + * @since 2.0 + */ +public interface ICompletionRequestor { +/** + * Code assist notification of an anonymous type declaration completion. + * @param superTypePackageName Name of the package that contains the super type of this + * new anonymous type declaration . + * + * @param superTypeName Name of the super type of this new anonymous type declaration. + * + * @param parameterPackageNames Names of the packages in which the parameter types are declared. + * Should contain as many elements as parameterTypeNames. + * + * @param parameterTypeNames Names of the parameters types. + * Should contain as many elements as parameterPackageNames. + * + * @param completionName The completion for the anonymous type declaration. + * Can include zero, one or two brackets. If the closing bracket is included, + * then the cursor should be placed before it. + * + * @param modifiers The modifiers of the constructor. + * + * @param completionStart The start position of insertion of the name of this new anonymous type declaration. + * + * @param completionEnd The end position of insertion of the name of this new anonymous type declaration. + * + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Base types are in the form "int" or "boolean". + * Array types are in the qualified form "M[]" or "int[]". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + * + * NOTE: parameter names can be retrieved from the source model after the user selects a specific method. + */ +void acceptAnonymousType( + char[] superTypePackageName, + char[] superTypeName, + char[][] parameterPackageNames, + char[][] parameterTypeNames, + char[][] parameterNames, + char[] completionName, + int modifiers, + int completionStart, + int completionEnd, + int relevance); +/** + * Code assist notification of a class completion. + * + * @param packageName Declaring package name of the class. + * @param className Name of the class. + * @param completionName The completion for the class. Can include ';' for imported classes. + * @param modifiers The modifiers of the class. + * @param completionStart The start position of insertion of the name of the class. + * @param completionEnd The end position of insertion of the name of the class. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ +void acceptClass( + char[] packageName, + char[] className, + char[] completionName, + int modifiers, + int completionStart, + int completionEnd, + int relevance); +/** + * Code assist notification of a compilation error detected during completion. + * @param error Only problems which are categorized as non-syntax errors are notified to the + * requestor, warnings are silently ignored. + * In case an error got signalled, no other completions might be available, + * therefore the problem message should be presented to the user. + * The source positions of the problem are related to the source where it was + * detected (might be in another compilation unit, if it was indirectly requested + * during the code assist process). + * Note: the problem knows its originating file name. + */ +void acceptError(IProblem error); +/** + * Code assist notification of a field completion. + * + * @param declaringTypePackageName Name of the package in which the type that contains this field is declared. + * @param declaringTypeName Name of the type declaring this new field. + * @param name Name of the field. + * @param typePackageName Name of the package in which the type of this field is declared. + * @param typeName Name of the type of this field. + * @param completionName The completion for the field. + * @param modifiers The modifiers of this field. + * @param completionStart The start position of insertion of the name of this field. + * @param completionEnd The end position of insertion of the name of this field. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Base types are in the form "int" or "boolean". + * Array types are in the qualified form "M[]" or "int[]". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ +void acceptField( + char[] declaringTypePackageName, + char[] declaringTypeName, + char[] name, + char[] typePackageName, + char[] typeName, + char[] completionName, + int modifiers, + int completionStart, + int completionEnd, + int relevance); +/** + * Code assist notification of an interface completion. + * + * @param packageName Declaring package name of the interface. + * @param className Name of the interface. + * @param completionName The completion for the interface. Can include ';' for imported interfaces. + * @param modifiers The modifiers of the interface. + * @param completionStart The start position of insertion of the name of the interface. + * @param completionEnd The end position of insertion of the name of the interface. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ +void acceptInterface( + char[] packageName, + char[] interfaceName, + char[] completionName, + int modifiers, + int completionStart, + int completionEnd, + int relevance); +/** + * Code assist notification of a keyword completion. + * @param keywordName The keyword source. + * @param completionStart The start position of insertion of the name of this keyword. + * @param completionEnd The end position of insertion of the name of this keyword. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + */ +void acceptKeyword(char[] keywordName, int completionStart, int completionEnd, int relevance); +/** + * Code assist notification of a label completion. + * + * @param labelName The label source. + * @param completionStart The start position of insertion of the name of this label. + * @param completionEnd The end position of insertion of the name of this label. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + */ +void acceptLabel(char[] labelName, int completionStart, int completionEnd, int relevance); +/** + * Code assist notification of a local variable completion. + * + * @param name Name of the new local variable. + * @param typePackageName Name of the package in which the type of this new local variable is declared. + * @param typeName Name of the type of this new local variable. + * @param modifiers The modifiers of this new local variable. + * @param completionStart The start position of insertion of the name of this new local variable. + * @param completionEnd The end position of insertion of the name of this new local variable. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Base types are in the form "int" or "boolean". + * Array types are in the qualified form "M[]" or "int[]". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ +void acceptLocalVariable( + char[] name, + char[] typePackageName, + char[] typeName, + int modifiers, + int completionStart, + int completionEnd, + int relevance); +/** + * Code assist notification of a method completion. + * + * @param declaringTypePackageName Name of the package in which the type that contains this new method is declared. + * @param declaringTypeName Name of the type declaring this new method. + * @param selector Name of the new method. + * @param parameterPackageNames Names of the packages in which the parameter types are declared. + * Should contain as many elements as parameterTypeNames. + * @param parameterTypeNames Names of the parameters types. + * Should contain as many elements as parameterPackageNames. + * @param returnTypePackageName Name of the package in which the return type is declared. + * @param returnTypeName Name of the return type of this new method, should be null for a constructor. + * @param completionName The completion for the method. Can include zero, one or two brackets. If the closing bracket is included, then the cursor should be placed before it. + * @param modifiers The modifiers of this new method. + * @param completionStart The start position of insertion of the name of this new method. + * @param completionEnd The end position of insertion of the name of this new method. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Base types are in the form "int" or "boolean". + * Array types are in the qualified form "M[]" or "int[]". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + * + * NOTE: parameter names can be retrieved from the source model after the user selects a specific method. + */ +void acceptMethod( + char[] declaringTypePackageName, + char[] declaringTypeName, + char[] selector, + char[][] parameterPackageNames, + char[][] parameterTypeNames, + char[][] parameterNames, + char[] returnTypePackageName, + char[] returnTypeName, + char[] completionName, + int modifiers, + int completionStart, + int completionEnd, + int relevance); + +/** + * Code assist notification of a method completion. + * + * @param declaringTypePackageName Name of the package in which the type that contains this new method is declared. + * @param declaringTypeName Name of the type declaring this new method. + * @param selector Name of the new method. + * @param parameterPackageNames Names of the packages in which the parameter types are declared. + * Should contain as many elements as parameterTypeNames. + * @param parameterTypeNames Names of the parameters types. + * Should contain as many elements as parameterPackageNames. + * @param returnTypePackageName Name of the package in which the return type is declared. + * @param returnTypeName Name of the return type of this new method, should be null for a constructor. + * @param completionName The completion for the method. Can include zero, one or two brackets. If the closing bracket is included, then the cursor should be placed before it. + * @param modifiers The modifiers of this new method. + * @param completionStart The start position of insertion of the name of this new method. + * @param completionEnd The end position of insertion of the name of this new method. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Base types are in the form "int" or "boolean". + * Array types are in the qualified form "M[]" or "int[]". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + * + * NOTE: parameter names can be retrieved from the source model after the user selects a specific method. + */ +void acceptMethodDeclaration( + char[] declaringTypePackageName, + char[] declaringTypeName, + char[] selector, + char[][] parameterPackageNames, + char[][] parameterTypeNames, + char[][] parameterNames, + char[] returnTypePackageName, + char[] returnTypeName, + char[] completionName, + int modifiers, + int completionStart, + int completionEnd, + int relevance); +/** + * Code assist notification of a modifier completion. + * + * @param modifierName The new modifier. + * @param completionStart The start position of insertion of the name of this new modifier. + * @param completionEnd The end position of insertion of the name of this new modifier. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + */ +void acceptModifier(char[] modifierName, int completionStart, int completionEnd, int relevance); +/** + * Code assist notification of a package completion. + * + * @param packageName The package name. + * @param completionName The completion for the package. Can include '.*;' for imports. + * @param completionStart The start position of insertion of the name of this new package. + * @param completionEnd The end position of insertion of the name of this new package. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package names are presented in their readable form: + * Package names are in the form "a.b.c". + * The default package is represented by an empty array. + */ +void acceptPackage( + char[] packageName, + char[] completionName, + int completionStart, + int completionEnd, + int relevance); +/** + * Code assist notification of a type completion. + * + * @param packageName Declaring package name of the type. + * @param typeName Name of the type. + * @param completionName The completion for the type. Can include ';' for imported types. + * @param completionStart The start position of insertion of the name of the type. + * @param completionEnd The end position of insertion of the name of the type. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ +void acceptType( + char[] packageName, + char[] typeName, + char[] completionName, + int completionStart, + int completionEnd, + int relevance); + +/** + * Code assist notification of a variable name completion. + * + * @param typePackageName Name of the package in which the type of this variable is declared. + * @param typeName Name of the type of this variable. + * @param name Name of the variable. + * @param completionName The completion for the variable. + * @param completionStart The start position of insertion of the name of this variable. + * @param completionEnd The end position of insertion of the name of this variable. + * @param relevance The relevance of the completion proposal + * It is a positive integer which are used for determine if this proposal is more relevant than another proposal. + * This value can only be used for compare relevance. A proposal is more relevant than another if his relevance + * value is higher. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Base types are in the form "int" or "boolean". + * Array types are in the qualified form "M[]" or "int[]". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ +void acceptVariableName( + char[] typePackageName, + char[] typeName, + char[] name, + char[] completionName, + int completionStart, + int completionEnd, + int relevance); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IField.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IField.java new file mode 100644 index 0000000..51facdc --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IField.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * Represents a field declared in a type. + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface IField extends IMember { +/** + * Returns the constant value associated with this field + * or null if this field has none. + * Returns either a subclass of Number, or a String, + * depending on the type of the field. + * For example, if the field is of type short, this returns + * a Short. + * + * @return the constant value associated with this field or null if this field has none. + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +public Object getConstant() throws JavaModelException; +/** + * Returns the simple name of this field. + * @return the simple name of this field. + */ +String getElementName(); +/** + * Returns the type signature of this field. + * + * @see Signature + * @return the type signature of this field. + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +String getTypeSignature() throws JavaModelException; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IInitializer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IInitializer.java new file mode 100644 index 0000000..5614f8d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IInitializer.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * Represents a stand-alone instance or class (static) initializer in a type. + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface IInitializer extends IMember { +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java new file mode 100644 index 0000000..ef4851d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java @@ -0,0 +1,275 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; + +/** + * Common protocol for all elements provided by the Java model. + * Java model elements are exposed to clients as handles to the actual underlying element. + * The Java model may hand out any number of handles for each element. Handles + * that refer to the same element are guaranteed to be equal, but not necessarily identical. + *

    + * Methods annotated as "handle-only" do not require underlying elements to exist. + * Methods that require underlying elements to exist throw + * a JavaModelException when an underlying element is missing. + * JavaModelException.isDoesNotExist can be used to recognize + * this common special case. + *

    + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface IJavaElement extends IAdaptable { + + /** + * Constant representing a Java model (workspace level object). + * A Java element with this type can be safely cast to IJavaModel. + */ + public static final int JAVA_MODEL = 1; + + /** + * Constant representing a Java project. + * A Java element with this type can be safely cast to IJavaProject. + */ + public static final int JAVA_PROJECT = 2; + + /** + * Constant representing a package fragment root. + * A Java element with this type can be safely cast to IPackageFragmentRoot. + */ + public static final int PACKAGE_FRAGMENT_ROOT = 3; + + /** + * Constant representing a package fragment. + * A Java element with this type can be safely cast to IPackageFragment. + */ + public static final int PACKAGE_FRAGMENT = 4; + + /** + * Constant representing a Java compilation unit. + * A Java element with this type can be safely cast to ICompilationUnit. + */ + public static final int COMPILATION_UNIT = 5; + + /** + * Constant representing a class file. + * A Java element with this type can be safely cast to IClassFile. + */ + public static final int CLASS_FILE = 6; + + /** + * Constant representing a type (a class or interface). + * A Java element with this type can be safely cast to IType. + */ + public static final int TYPE = 7; + + /** + * Constant representing a field. + * A Java element with this type can be safely cast to IField. + */ + public static final int FIELD = 8; + + /** + * Constant representing a method or constructor. + * A Java element with this type can be safely cast to IMethod. + */ + public static final int METHOD = 9; + + /** + * Constant representing a stand-alone instance or class initializer. + * A Java element with this type can be safely cast to IInitializer. + */ + public static final int INITIALIZER = 10; + + /** + * Constant representing a package declaration within a compilation unit. + * A Java element with this type can be safely cast to IPackageDeclaration. + */ + public static final int PACKAGE_DECLARATION = 11; + + /** + * Constant representing all import declarations within a compilation unit. + * A Java element with this type can be safely cast to IImportContainer. + */ + public static final int IMPORT_CONTAINER = 12; + + /** + * Constant representing an import declaration within a compilation unit. + * A Java element with this type can be safely cast to IImportDeclaration. + */ + public static final int IMPORT_DECLARATION = 13; + +/** + * Returns whether this Java element exists in the model. + * + * @return true if this element exists in the Java model + */ +boolean exists(); +/** + * Returns the first ancestor of this Java element that has the given type. + * Returns null if no such an ancestor can be found. + * This is a handle-only method. + * + * @param ancestorType the given type + * @return the first ancestor of this Java element that has the given type, null if no such an ancestor can be found + * @since 2.0 + */ +IJavaElement getAncestor(int ancestorType); +/** + * Returns the resource that corresponds directly to this element, + * or null if there is no resource that corresponds to + * this element. + *

    + * For example, the corresponding resource for an ICompilationUnit + * is its underlying IFile. The corresponding resource for + * an IPackageFragment that is not contained in an archive + * is its underlying IFolder. An IPackageFragment + * contained in an archive has no corresponding resource. Similarly, there + * are no corresponding resources for IMethods, + * IFields, etc. + *

    + * + * @return the corresponding resource, or null if none + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +IResource getCorrespondingResource() throws JavaModelException; +/** + * Returns the name of this element. This is a handle-only method. + * + * @return the element name + */ +String getElementName(); +/** + * Returns this element's kind encoded as an integer. + * This is a handle-only method. + * + * @return the kind of element; one of the constants declared in + * IJavaElement + * @see IJavaElement + */ +public int getElementType(); +/** + * Returns a string representation of this element handle. The format of + * the string is not specified; however, the identifier is stable across + * workspace sessions, and can be used to recreate this handle via the + * JavaCore.create(String) method. + * + * @return the string handle identifier + * @see JavaCore#create(java.lang.String) + */ +String getHandleIdentifier(); +/** + * Returns the Java model. + * This is a handle-only method. + * + * @return the Java model + */ +IJavaModel getJavaModel(); +/** + * Returns the Java project this element is contained in, + * or null if this element is not contained in any Java project + * (for instance, the IJavaModel is not contained in any Java + * project). + * This is a handle-only method. + * + * @return the containing Java project, or null if this element is + * not contained in a Java project + */ +IJavaProject getJavaProject(); +/** + * Returns the first openable parent. If this element is openable, the element + * itself is returned. Returns null if this element doesn't have + * an openable parent. + * This is a handle-only method. + * + * @return the first openable parent or null if this element doesn't have + * an openable parent. + * @since 2.0 + */ +IOpenable getOpenable(); +/** + * Returns the element directly containing this element, + * or null if this element has no parent. + * This is a handle-only method. + * + * @return the parent element, or null if this element has no parent + */ +IJavaElement getParent(); +/** + * Returns the path to the innermost resource enclosing this element. + * If this element is not included in an external archive, + * the path returned is the full, absolute path to the underlying resource, + * relative to the workbench. + * If this element is included in an external archive, + * the path returned is the absolute path to the archive in the file system. + * This is a handle-only method. + * + * @return the path to the innermost resource enclosing this element + * @since 2.0 + */ +IPath getPath(); +/** + * Returns the innermost resource enclosing this element. + * If this element is included in an archive and this archive is not external, + * this is the underlying resource corresponding to the archive. + * If this element is included in an external archive, null + * is returned. + * If this element is a working copy, null is returned. + * This is a handle-only method. + * + * @return the innermost resource enclosing this element, null if this + * element is a working copy or is included in an external archive + * @since 2.0 + */ +IResource getResource(); +/** + * Returns the smallest underlying resource that contains + * this element, or null if this element is not contained + * in a resource. + * + * @return the underlying resource, or null if none + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its underlying resource + */ +IResource getUnderlyingResource() throws JavaModelException; +/** + * Returns whether this Java element is read-only. An element is read-only + * if its structure cannot be modified by the java model. + *

    + * Note this is different from IResource.isReadOnly(). For example, .jar + * files are read-only as the java model doesn't know how to add/remove + * elements in this file, but the underlying IFile can be writable. + *

    + * This is a handle-only method. + * + * @return true if this element is read-only + */ +boolean isReadOnly(); +/** + * Returns whether the structure of this element is known. For example, for a + * compilation unit that could not be parsed, false is returned. + * If the structure of an element is unknown, navigations will return reasonable + * defaults. For example, getChildren will return an empty collection. + *

    + * Note: This does not imply anything about consistency with the + * underlying resource/buffer contents. + *

    + * + * @return true if the structure of this element is known + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +boolean isStructureKnown() throws JavaModelException; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java new file mode 100644 index 0000000..a9858d4 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java @@ -0,0 +1,221 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * Represent the root Java element corresponding to the workspace. + * Since there is only one such root element, it is commonly referred to as + * the Java model element. + * The Java model element needs to be opened before it can be navigated or manipulated. + * The Java model element has no parent (it is the root of the Java element + * hierarchy). Its children are IJavaProjects. + *

    + * This interface provides methods for performing copy, move, rename, and + * delete operations on multiple Java elements. + *

    + *

    + * This interface is not intended to be implemented by clients. An instance + * of one of these handles can be created via + * JavaCore.create(workspace.getRoot()). + *

    + * + * @see JavaCore#create(org.eclipse.core.resources.IWorkspaceRoot) + */ +public interface IJavaModel extends IJavaElement, IOpenable, IParent { +/** + * Copies the given elements to the specified container(s). + * If one container is specified, all elements are copied to that + * container. If more than one container is specified, the number of + * elements and containers must match, and each element is copied to + * its associated container. + *

    + * Optionally, each copy can positioned before a sibling + * element. If null is specified for a given sibling, the copy + * is inserted as the last child of its associated container. + *

    + *

    + * Optionally, each copy can be renamed. If + * null is specified for the new name, the copy + * is not renamed. + *

    + *

    + * Optionally, any existing child in the destination container with + * the same name can be replaced by specifying true for + * force. Otherwise an exception is thrown in the event that a name + * collision occurs. + *

    + * + * @param elements the elements to copy + * @param containers the container, or list of containers + * @param siblings the list of siblings element any of which may be + * null; or null + * @param renamings the list of new names any of which may be + * null; or null + * @param replace true if any existing child in a target container + * with the target name should be replaced, and false to throw an + * exception in the event of a name collision + * @param monitor a progress monitor + * @exception JavaModelException if an element could not be copied. Reasons include: + * + */ +void copy(IJavaElement[] elements, IJavaElement[] containers, IJavaElement[] siblings, String[] renamings, boolean replace, IProgressMonitor monitor) throws JavaModelException; +/** + * Deletes the given elements, forcing the operation if necessary and specified. + * + * @param elements the elements to delete + * @param force a flag controlling whether underlying resources that are not + * in sync with the local file system will be tolerated + * @param monitor a progress monitor + * @exception JavaModelException if an element could not be deleted. Reasons include: + * + */ +void delete(IJavaElement[] elements, boolean force, IProgressMonitor monitor) throws JavaModelException; +/** + * Returns the Java project with the given name. This is a handle-only method. + * The project may or may not exist. + * + * @return the Java project with the given name + */ +IJavaProject getJavaProject(String name); +/** + * Returns the Java projects in this Java model, or an empty array if there + * are none. + * + * @return the Java projects in this Java model, or an empty array if there + * are none + * @exception JavaModelException if this request fails. + */ +IJavaProject[] getJavaProjects() throws JavaModelException; +/** + * Returns the workspace associated with this Java model. + * + * @return the workspace associated with this Java model + */ +IWorkspace getWorkspace(); +/** + * Moves the given elements to the specified container(s). + * If one container is specified, all elements are moved to that + * container. If more than one container is specified, the number of + * elements and containers must match, and each element is moved to + * its associated container. + *

    + * Optionally, each element can positioned before a sibling + * element. If null is specified for sibling, the element + * is inserted as the last child of its associated container. + *

    + *

    + * Optionally, each element can be renamed. If + * null is specified for the new name, the element + * is not renamed. + *

    + *

    + * Optionally, any existing child in the destination container with + * the same name can be replaced by specifying true for + * force. Otherwise an exception is thrown in the event that a name + * collision occurs. + *

    + * + * @param elements the elements to move + * @param containers the container, or list of containers + * @param siblings the list of siblings element any of which may be + * null; or null + * @param renamings the list of new names any of which may be + * null; or null + * @param replace true if any existing child in a target container + * with the target name should be replaced, and false to throw an + * exception in the event of a name collision + * @param monitor a progress monitor + * @exception JavaModelException if an element could not be moved. Reasons include: + * + * + * @exception IllegalArgumentException any element or container is null + */ +void move(IJavaElement[] elements, IJavaElement[] containers, IJavaElement[] siblings, String[] renamings, boolean replace, IProgressMonitor monitor) throws JavaModelException; + +/** + * Triggers an update of the JavaModel with respect to the referenced external archives. + * This operation will issue a JavaModel delta describing the discovered changes, in term + * of Java element package fragment roots added, removed or changed. + * Note that a collection of elements can be passed so as to narrow the set of archives + * to refresh (passing null along is equivalent to refreshing the entire mode). + * The elements can be: + * + *

    In case an archive is used by multiple projects, the delta issued will account for + * all of them. This means that even if a project was not part of the elements scope, it + * may still be notified of changes if it is referencing a library comprised in the scope. + *

    + * @param elementsScope - a collection of elements defining the scope of the refresh + * @param monitor - a progress monitor used to report progress + * @exception JavaModelException in one of the corresponding situation: + *

    + * + * @see IJavaElementDelta + * @since 2.0 + */ +void refreshExternalArchives(IJavaElement[] elementsScope, IProgressMonitor monitor) throws JavaModelException; + +/** + * Renames the given elements as specified. + * If one container is specified, all elements are renamed within that + * container. If more than one container is specified, the number of + * elements and containers must match, and each element is renamed within + * its associated container. + * + * @param elements the elements to rename + * @param destinations the container, or list of containers + * @param names the list of new names + * @param replace true if an existing child in a target container + * with the target name should be replaced, and false to throw an + * exception in the event of a name collision + * @param monitor a progress monitor + * @exception JavaModelException if an element could not be renamed. Reasons include: + * + */ +void rename(IJavaElement[] elements, IJavaElement[] destinations, String[] names, boolean replace, IProgressMonitor monitor) throws JavaModelException; + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java new file mode 100644 index 0000000..27a8452 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; + +/** + * Represents the outcome of an Java model operation. Status objects are + * used inside JavaModelException objects to indicate what went + * wrong. + *

    + * Java model status object are distinguished by their plug-in id: + * getPlugin returns "net.sourceforge.phpdt.core". + * getCode returns one of the status codes declared in + * IJavaModelStatusConstants. + *

    + *

    + * A Java model status may also carry additional information (that is, in + * addition to the information defined in IStatus): + *

    + *

    + * This interface is not intended to be implemented by clients. + *

    + * + * @see org.eclipse.core.runtime.IStatus + * @see IJavaModelStatusConstants + */ +public interface IJavaModelStatus extends IStatus { +/** + * Returns any Java elements associated with the failure (see specification + * of the status code), or an empty array if no elements are related to this + * particular status code. + * + * @return the list of Java element culprits + * @see IJavaModelStatusConstants + */ +IJavaElement[] getElements(); +/** + * Returns the path associated with the failure (see specification + * of the status code), or null if the failure is not + * one of DEVICE_PATH, INVALID_PATH, + * PATH_OUTSIDE_PROJECT, or RELATIVE_PATH. + * + * @return the path that caused the failure, or null if none + * @see IJavaModelStatusConstants#DEVICE_PATH + * @see IJavaModelStatusConstants#INVALID_PATH + * @see IJavaModelStatusConstants#PATH_OUTSIDE_PROJECT + * @see IJavaModelStatusConstants#RELATIVE_PATH + */ +IPath getPath(); +/** + * Returns the string associated with the failure (see specification + * of the status code), or null if no string is related to this + * particular status code. + * + * @return the string culprit, or null if none + * @see IJavaModelStatusConstants + */ +String getString(); +/** + * Returns whether this status indicates that a Java model element does not exist. + * This convenience method is equivalent to + * getCode() == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST. + * + * @return true if the status code indicates that a Java model + * element does not exist + * @see IJavaModelStatusConstants#ELEMENT_DOES_NOT_EXIST + */ +boolean isDoesNotExist(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java new file mode 100644 index 0000000..7eea239 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * Status codes used with Java model status objects. + *

    + * This interface declares constants only; it is not intended to be implemented + * or extended. + *

    + * + * @see IJavaModelStatus + * @see org.eclipse.core.runtime.IStatus#getCode() + */ +public interface IJavaModelStatusConstants { + + /** + * Status constant indicating that a container path was resolved + * to invalid entries (null or container). + * + * @since 2.0 + */ + public static final int INVALID_CP_CONTAINER_ENTRY = 962; + + /** + * Status constant indicating that a container path was not resolvable + * indicating either the referred container is undefined, unbound. + * + * @since 2.0 + */ + public static final int CP_CONTAINER_PATH_UNBOUND = 963; + + /** + * Status constant indicating that a classpath entry was invalid + */ + public static final int INVALID_CLASSPATH = 964; + + /** + * Status constant indicating that a variable path was not resolvable + * indicating either the referred variable is undefined, unbound or the resolved + * variable path does not correspond to an existing file or folder. + */ + public static final int CP_VARIABLE_PATH_UNBOUND = 965; + + /** + * Status constant indicating a core exception occurred. + * Use getException to retrieve a CoreException. + */ + public static final int CORE_EXCEPTION = 966; + + /** + * Status constant indicating one or more of the elements + * supplied are not of a valid type for the operation to + * process. + * The element(s) can be retrieved using getElements on the status object. + */ + public static final int INVALID_ELEMENT_TYPES = 967; + + /** + * Status constant indicating that no elements were + * provided to the operation for processing. + */ + public static final int NO_ELEMENTS_TO_PROCESS = 968; + + /** + * Status constant indicating that one or more elements + * supplied do not exist. + * The element(s) can be retrieved using getElements on the status object. + * + * @see IJavaModelStatus#isDoesNotExist + */ + public static final int ELEMENT_DOES_NOT_EXIST = 969; + + /** + * Status constant indicating that a null path was + * supplied to the operation. + */ + public static final int NULL_PATH = 970; + + /** + * Status constant indicating that a path outside of the + * project was supplied to the operation. The path can be retrieved using + * getPath on the status object. + */ + public static final int PATH_OUTSIDE_PROJECT = 971; + + /** + * Status constant indicating that a relative path + * was supplied to the operation when an absolute path is + * required. The path can be retrieved using getPath on the + * status object. + */ + public static final int RELATIVE_PATH = 972; + + /** + * Status constant indicating that a path specifying a device + * was supplied to the operation when a path with no device is + * required. The path can be retrieved using getPath on the + * status object. + */ + public static final int DEVICE_PATH = 973; + + /** + * Status constant indicating that a string + * was supplied to the operation that was null. + */ + public static final int NULL_STRING = 974; + + /** + * Status constant indicating that the operation encountered + * a read-only element. + * The element(s) can be retrieved using getElements on the status object. + */ + public static final int READ_ONLY = 976; + + /** + * Status constant indicating that a naming collision would occur + * if the operation proceeded. + */ + public static final int NAME_COLLISION = 977; + + /** + * Status constant indicating that a destination provided for a copy/move/rename operation + * is invalid. + * The destination element can be retrieved using getElements on the status object. + */ + public static final int INVALID_DESTINATION = 978; + + /** + * Status constant indicating that a path provided to an operation + * is invalid. The path can be retrieved using getPath on the + * status object. + */ + public static final int INVALID_PATH = 979; + + /** + * Status constant indicating the given source position is out of bounds. + */ + public static final int INDEX_OUT_OF_BOUNDS = 980; + + /** + * Status constant indicating there is an update conflict + * for a working copy. The compilation unit on which the + * working copy is based has changed since the working copy + * was created. + */ + public static final int UPDATE_CONFLICT = 981; + + /** + * Status constant indicating that null was specified + * as a name argument. + */ + public static final int NULL_NAME = 982; + + /** + * Status constant indicating that a name provided is not syntactically correct. + * The name can be retrieved from getString. + */ + public static final int INVALID_NAME = 983; + + /** + * Status constant indicating that the specified contents + * are not valid. + */ + public static final int INVALID_CONTENTS = 984; + + /** + * Status constant indicating that an java.io.IOException + * occurred. + */ + public static final int IO_EXCEPTION = 985; + + /** + * Status constant indicating that a DOMException + * occurred. + */ + public static final int DOM_EXCEPTION = 986; + + /** + * Status constant indicating that a TargetException + * occurred. + */ + public static final int TARGET_EXCEPTION = 987; + + /** + * Status constant indicating that the Java builder + * could not be initialized. + */ + public static final int BUILDER_INITIALIZATION_ERROR = 990; + + /** + * Status constant indicating that the Java builder's last built state + * could not be serialized or deserialized. + */ + public static final int BUILDER_SERIALIZATION_ERROR = 991; + + /** + * Status constant indicating that an error was encountered while + * trying to evaluate a code snippet, or other item. + */ + public static final int EVALUATION_ERROR = 992; + + /** + * Status constant indicating that a sibling specified is not valid. + */ + public static final int INVALID_SIBLING = 993; + + /** + * Status indicating that a Java element could not be created because + * the underlying resource is invalid. + * @see JavaCore + */ + public static final int INVALID_RESOURCE = 995; + + /** + * Status indicating that a Java element could not be created because + * the underlying resource is not of an appropriate type. + * @see JavaCore + */ + public static final int INVALID_RESOURCE_TYPE = 996; + + /** + * Status indicating that a Java element could not be created because + * the project owning underlying resource does not have the Java nature. + * @see JavaCore + */ + public static final int INVALID_PROJECT = 997; + + /** + * Status indicating that the package declaration in a ICompilationUnit + * does not correspond to the IPackageFragment it belongs to. + * The getString method of the associated status object + * gives the name of the package in which the ICompilationUnit is + * declared. + */ + public static final int INVALID_PACKAGE = 998; + + /** + * Status indicating that the corresponding resource has no local contents yet. + * This might happen when attempting to use a resource before its contents + * has been made locally available. + */ + public static final int NO_LOCAL_CONTENTS = 999; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaProject.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaProject.java new file mode 100644 index 0000000..c9e71e7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaProject.java @@ -0,0 +1,503 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IPath; + +//import net.sourceforge.phpdt.core.eval.IEvaluationContext; + +/** + * A Java project represents a view of a project resource in terms of Java + * elements such as package fragments, types, methods and fields. + * A project may contain several package roots, which contain package fragments. + * A package root corresponds to an underlying folder or JAR. + *

    + * Each Java project has a classpath, defining which folders contain source code and + * where required libraries are located. Each Java project also has an output location, + * defining where the builder writes .class files. A project that + * references packages in another project can access the packages by including + * the required project in a classpath entry. The Java model will present the + * source elements in the required project, and when building, the compiler will + * use the binaries from that project (that is, the output location of the + * required project is used as a library). The classpath format is a sequence + * of classpath entries describing the location and contents of package fragment + * roots. + *

    + * Java project elements need to be opened before they can be navigated or manipulated. + * The children of a Java project are the package fragment roots that are + * defined by the classpath and contained in this project (in other words, it + * does not include package fragment roots for other projects). + *

    + *

    + * This interface is not intended to be implemented by clients. An instance + * of one of these handles can be created via + * JavaCore.create(project). + *

    + * + * @see JavaCore#create(org.eclipse.core.resources.IProject) + * @see IClasspathEntry + */ +public interface IJavaProject extends IParent, IJavaElement, IOpenable { + + /** + * Returns the IJavaElement corresponding to the given + * classpath-relative path, or null if no such + * IJavaElement is found. The result is one of an + * ICompilationUnit, IClassFile, or + * IPackageFragment. + *

    + * When looking for a package fragment, there might be several potential + * matches; only one of them is returned. + * + *

    For example, the path "java/lang/Object.java", would result in the + * ICompilationUnit or IClassFile corresponding to + * "java.lang.Object". The path "java/lang" would result in the + * IPackageFragment for "java.lang". + * @param path the given classpath-relative path + * @exception JavaModelException if the given path is null + * or absolute + * @return the IJavaElement corresponding to the given + * classpath-relative path, or null if no such + * IJavaElement is found + */ + IJavaElement findElement(IPath path) throws JavaModelException; + + /** + * Returns the first existing package fragment on this project's classpath + * whose path matches the given (absolute) path, or null if none + * exist. + * The path can be: + * - internal to the workbench: "/Project/src" + * - external to the workbench: "c:/jdk/classes.zip/java/lang" + * @param path the given absolute path + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @return the first existing package fragment on this project's classpath + * whose path matches the given (absolute) path, or null if none + * exist + */ + //IPackageFragment findPackageFragment(IPath path) throws JavaModelException; + + /** + * Returns the existing package fragment root on this project's classpath + * whose path matches the given (absolute) path, or null if + * one does not exist. + * The path can be: + * - internal to the workbench: "/Compiler/src" + * - external to the workbench: "c:/jdk/classes.zip" + * @param path the given absolute path + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @return the existing package fragment root on this project's classpath + * whose path matches the given (absolute) path, or null if + * one does not exist + */ + // IPackageFragmentRoot findPackageFragmentRoot(IPath path) + // throws JavaModelException; + /** + * Returns the first type found following this project's classpath + * with the given fully qualified name or null if none is found. + * The fully qualified name is a dot-separated name. For example, + * a class B defined as a member type of a class A in package x.y should have a + * the fully qualified name "x.y.A.B". + * + * @param fullyQualifiedName the given fully qualified name + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @return the first type found following this project's classpath + * with the given fully qualified name or null if none is found + * @see IType#getFullyQualifiedName(char) + * @since 2.0 + */ + IType findType(String fullyQualifiedName) throws JavaModelException; + /** + * Returns the first type found following this project's classpath + * with the given package name and type qualified name + * or null if none is found. + * The package name is a dot-separated name. + * The type qualified name is also a dot-separated name. For example, + * a class B defined as a member type of a class A should have the + * type qualified name "A.B". + * + * @param packageName the given package name + * @param typeQualifiedName the given type qualified name + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @return the first type found following this project's classpath + * with the given package name and type qualified name + * or null if none is found + * @see IType#getTypeQualifiedName(char) + * @since 2.0 + */ + IType findType(String packageName, String typeQualifiedName) throws JavaModelException; + + /** + * Returns all of the existing package fragment roots that exist + * on the classpath, in the order they are defined by the classpath. + * + * @return all of the existing package fragment roots that exist + * on the classpath + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ + // IPackageFragmentRoot[] getAllPackageFragmentRoots() throws JavaModelException; + + /** + * Returns an array of non-Java resources directly contained in this project. + * It does not transitively answer non-Java resources contained in folders; + * these would have to be explicitly iterated over. + * @return an array of non-Java resources directly contained in this project + */ + Object[] getNonJavaResources() throws JavaModelException; + + /** + * Returns the full path to the location where the builder writes + * .class files. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @return the full path to the location where the builder writes + * .class files + */ + IPath getOutputLocation() throws JavaModelException; + + /** + * Returns a package fragment root for the JAR at the specified file system path. + * This is a handle-only method. The underlying java.io.File + * may or may not exist. No resource is associated with this local JAR + * package fragment root. + * + * @param jarPath the jars's file system path + * @return a package fragment root for the JAR at the specified file system path + */ + // IPackageFragmentRoot getPackageFragmentRoot(String jarPath); + + /** + * Returns a package fragment root for the given resource, which + * must either be a folder representing the top of a package hierarchy, + * or a .jar or .zip file. + * This is a handle-only method. The underlying resource may or may not exist. + * + * @param resource the given resource + * @return a package fragment root for the given resource, which + * must either be a folder representing the top of a package hierarchy, + * or a .jar or .zip file + */ + // IPackageFragmentRoot getPackageFragmentRoot(IResource resource); + + /** + * Returns all of the package fragment roots contained in this + * project, identified on this project's resolved classpath. The result + * does not include package fragment roots in other projects referenced + * on this project's classpath. + * + *

    NOTE: This is equivalent to getChildren(). + * + * @return all of the package fragment roots contained in this + * project, identified on this project's resolved classpath + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ + // IPackageFragmentRoot[] getPackageFragmentRoots() throws JavaModelException; + + /** + * Returns the existing package fragment roots identified by the given entry. + * Note that a classpath entry that refers to another project may + * have more than one root (if that project has more than on root + * containing source), and classpath entries within the current + * project identify a single root. + *

    + * If the classpath entry denotes a variable, it will be resolved and return + * the roots of the target entry (empty if not resolvable). + *

    + * If the classpath entry denotes a container, it will be resolved and return + * the roots corresponding to the set of container entries (empty if not resolvable). + * + * @param entry the given entry + * @return the existing package fragment roots identified by the given entry + * @see IClasspathContainer + */ + // IPackageFragmentRoot[] getPackageFragmentRoots(IClasspathEntry entry); + + /** + * Returns all package fragments in all package fragment roots contained + * in this project. This is a convenience method. + * + * Note that the package fragment roots corresponds to the resolved + * classpath of the project. + * + * @return all package fragments in all package fragment roots contained + * in this project + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ + // IPackageFragment[] getPackageFragments() throws JavaModelException; + + /** + * Returns the IProject on which this IJavaProject + * was created. This is handle-only method. + * + * @return the IProject on which this IJavaProject + * was created + */ + IProject getProject(); + + /** + * This is a helper method returning the resolved classpath for the project, as a list of classpath entries, + * where all classpath variable entries have been resolved and substituted with their final target entries. + *

    + * A resolved classpath corresponds to a particular instance of the raw classpath bound in the context of + * the current values of the referred variables, and thus should not be persisted. + *

    + * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows + * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath + * can simply refer to some variables defining the proper locations of these external JARs. + *

    + * The boolean argument ignoreUnresolvedVariable allows to specify how to handle unresolvable variables, + * when set to true, missing variables are simply ignored, the resulting path is then only formed of the + * resolvable entries, without any indication about which variable(s) was ignored. When set to false, a + * JavaModelException will be thrown for the first unresolved variable (from left to right). + * + * @exception JavaModelException in one of the corresponding situation: + *

    + * @return + * @see IClasspathEntry + */ + // IClasspathEntry[] getExpandedClasspath(boolean ignoreUnresolvedVariable) + // throws JavaModelException; + + /** + * Returns the raw classpath for the project, as a list of classpath entries. This corresponds to the exact set + * of entries which were assigned using setRawClasspath, in particular such a classpath may contain + * classpath variable entries. Classpath variable entries can be resolved individually (see JavaCore#getClasspathVariable), + * or the full classpath can be resolved at once using the helper method getResolvedClasspath. + *

    + * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows + * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath + * can simply refer to some variables defining the proper locations of these external JARs. + *

    + * Note that in case the project isn't yet opened, the classpath will directly be read from the associated .classpath file. + *

    + * + * @return the raw classpath for the project, as a list of classpath entries + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @see IClasspathEntry + */ + // IClasspathEntry[] getRawClasspath() throws JavaModelException; + + /** + * Returns the names of the projects that are directly required by this + * project. A project is required if it is in its classpath. + * + * @return the names of the projects that are directly required by this + * project + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ + String[] getRequiredProjectNames() throws JavaModelException; + + /** + * This is a helper method returning the resolved classpath for the project, as a list of classpath entries, + * where all classpath variable entries have been resolved and substituted with their final target entries. + *

    + * A resolved classpath corresponds to a particular instance of the raw classpath bound in the context of + * the current values of the referred variables, and thus should not be persisted. + *

    + * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows + * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath + * can simply refer to some variables defining the proper locations of these external JARs. + *

    + * The boolean argument ignoreUnresolvedVariable allows to specify how to handle unresolvable variables, + * when set to true, missing variables are simply ignored, the resulting path is then only formed of the + * resolvable entries, without any indication about which variable(s) was ignored. When set to false, a + * JavaModelException will be thrown for the first unresolved variable (from left to right). + * + * @param ignoreUnresolvedVariable specify how to handle unresolvable variables + * @return the resolved classpath for the project, as a list of classpath entries, + * where all classpath variable entries have been resolved and substituted with their final target entries + * @exception JavaModelException in one of the corresponding situation: + *

    + * @see IClasspathEntry + */ + // IClasspathEntry[] getResolvedClasspath(boolean ignoreUnresolvedVariable) throws JavaModelException; + + /** + * Returns whether this project has been built at least once and thus whether it has a build state. + * @return true if this project has been built at least once, false otherwise + */ + boolean hasBuildState(); + + /** + * Returns whether setting this project's classpath to the given classpath entries + * would result in a cycle. + * + * If the set of entries contains some variables, those are resolved in order to determine + * cycles. + * + * @param entries the given classpath entries + * @return true if the given classpath entries would result in a cycle, false otherwise + */ + // boolean hasClasspathCycle(IClasspathEntry[] entries); + /** + * Returns whether the given element is on the classpath of this project. + * + * @param element the given element + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @return true if the given element is on the classpath of this project, false otherwise + * @since 2.0 + */ + boolean isOnClasspath(IJavaElement element) throws JavaModelException; + + /** + * Creates a new evaluation context. + * @return a new evaluation context. + */ + // IEvaluationContext newEvaluationContext(); + + /** + * Creates and returns a type hierarchy for all types in the given + * region, considering subtypes within that region. + * + * @param monitor the given progress monitor + * @param region the given region + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @exception IllegalArgumentException if region is null + * @return a type hierarchy for all types in the given + * region, considering subtypes within that region + */ + // ITypeHierarchy newTypeHierarchy(IRegion region, IProgressMonitor monitor) + // throws JavaModelException; + + /** + * Creates and returns a type hierarchy for the given type considering + * subtypes in the specified region. + * + * @param monitor the given monitor + * @param region the given region + * @param type the given type + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * + * @exception IllegalArgumentException if type or region is null + * @return a type hierarchy for the given type considering + * subtypes in the specified region + */ + // ITypeHierarchy newTypeHierarchy( + // IType type, + // IRegion region, + // IProgressMonitor monitor) + // throws JavaModelException; + + /** + * Sets the output location of this project to the location + * described by the given absolute path. + *

    + * + * @param path the given absolute path + * @param monitor the given progress monitor + * + * @exception JavaModelException if the classpath could not be set. Reasons include: + *

    + */ + void setOutputLocation(IPath path, IProgressMonitor monitor) throws JavaModelException; + + /** + * Sets the classpath of this project using a list of classpath entries. In particular such a classpath may contain + * classpath variable entries. Classpath variable entries can be resolved individually (see JavaCore#getClasspathVariable), + * or the full classpath can be resolved at once using the helper method getResolvedClasspath. + *

    + * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows + * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath + * can simply refer to some variables defining the proper locations of these external JARs. + *

    + * Setting the classpath to null specifies a default classpath + * (the project root). Setting the classpath to an empty array specifies an + * empty classpath. + *

    + * If a cycle is detected while setting this classpath, an error marker will be added + * to the project closing the cycle. + * To avoid this problem, use hasClasspathCycle(IClasspathEntry[] entries) + * before setting the classpath. + * + * @param entries a list of classpath entries + * @param monitor the given progress monitor + * @exception JavaModelException if the classpath could not be set. Reasons include: + *

    + * @see IClasspathEntry + */ + // void setRawClasspath(IClasspathEntry[] entries, IProgressMonitor monitor) + // throws JavaModelException; + + /** + * Sets the both the classpath of this project and its output location at once. + * The classpath is defined using a list of classpath entries. In particular such a classpath may contain + * classpath variable entries. Classpath variable entries can be resolved individually (see JavaCore#getClasspathVariable), + * or the full classpath can be resolved at once using the helper method getResolvedClasspath. + *

    + * A classpath variable provides an indirection level for better sharing a classpath. As an example, it allows + * a classpath to no longer refer directly to external JARs located in some user specific location. The classpath + * can simply refer to some variables defining the proper locations of these external JARs. + *

    + * Setting the classpath to null specifies a default classpath + * (the project root). Setting the classpath to an empty array specifies an + * empty classpath. + *

    + * If a cycle is detected while setting this classpath, an error marker will be added + * to the project closing the cycle. + * To avoid this problem, use hasClasspathCycle(IClasspathEntry[] entries) + * before setting the classpath. + * + * @param entries a list of classpath entries + * @param monitor the given progress monitor + * @param outputLocation the given output location + * + * @exception JavaModelException if the classpath could not be set. Reasons include: + *

    + * @see IClasspathEntry + * @since 2.0 + */ + // void setRawClasspath(IClasspathEntry[] entries, IPath outputLocation, IProgressMonitor monitor) + // throws JavaModelException; +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IMember.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IMember.java new file mode 100644 index 0000000..7e532ec --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IMember.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * Common protocol for Java elements that can be members of types. + * This set consists of IType, IMethod, + * IField, and IInitializer. + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface IMember extends IJavaElement, ISourceReference, ISourceManipulation { +/** + * Returns the class file in which this member is declared, or null + * if this member is not declared in a class file (for example, a source type). + * This is a handle-only method. + * + * @return the class file in which this member is declared, or null + * if this member is not declared in a class file (for example, a source type) + */ +// IClassFile getClassFile(); +/** + * Returns the compilation unit in which this member is declared, or null + * if this member is not declared in a compilation unit (for example, a binary type). + * This is a handle-only method. + * + * @return the compilation unit in which this member is declared, or null + * if this member is not declared in a compilation unit (for example, a binary type) + */ +ICompilationUnit getCompilationUnit(); +/** + * Returns the type in which this member is declared, or null + * if this member is not declared in a type (for example, a top-level type). + * This is a handle-only method. + * + * @return the type in which this member is declared, or null + * if this member is not declared in a type (for example, a top-level type) + */ +IType getDeclaringType(); +/** + * Returns the modifier flags for this member. The flags can be examined using class + * Flags. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the modifier flags for this member + * @see Flags + */ +int getFlags() throws JavaModelException; +/** + * Returns the source range of this member's simple name, + * or null if this member does not have a name + * (for example, an initializer), or if this member does not have + * associated source code (for example, a binary type). + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the source range of this member's simple name, + * or null if this member does not have a name + * (for example, an initializer), or if this member does not have + * associated source code (for example, a binary type) + */ +ISourceRange getNameRange() throws JavaModelException; +/** + * Returns whether this member is from a class file. + * This is a handle-only method. + * + * @return true if from a class file, and false if + * from a compilation unit + */ +boolean isBinary(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IMethod.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IMethod.java new file mode 100644 index 0000000..2dd7cc3 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IMethod.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * Represents a method (or constructor) declared in a type. + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface IMethod extends IMember { +/** + * Returns the simple name of this method. + * For a constructor, this returns the simple name of the declaring type. + * Note: This holds whether the constructor appears in a source or binary type + * (even though class files internally define constructor names to be "<init>"). + * For the class initialization methods in binary types, this returns + * the special name "<clinit>". + * This is a handle-only method. + */ +String getElementName(); +/** + * Returns the type signatures of the exceptions this method throws, + * in the order declared in the source. Returns an empty array + * if this method throws no exceptions. + * + *

    For example, a source method declaring "throws IOException", + * would return the array {"QIOException;"}. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the type signatures of the exceptions this method throws, + * in the order declared in the source, an empty array if this method throws no exceptions + * @see Signature + */ +String[] getExceptionTypes() throws JavaModelException; +/** + * Returns the number of parameters of this method. + * This is a handle-only method. + * + * @return the number of parameters of this method + */ +int getNumberOfParameters(); +/** + * Returns the names of parameters in this method. + * For binary types, these names are invented as "arg"+i, where i starts at 1 + * (even if source is associated with the binary). + * Returns an empty array if this method has no parameters. + * + *

    For example, a method declared as public void foo(String text, int length) + * would return the array {"text","length"}. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the names of parameters in this method, an empty array if this method has no parameters + */ +String[] getParameterNames() throws JavaModelException; +/** + * Returns the type signatures for the parameters of this method. + * Returns an empty array if this method has no parameters. + * This is a handle-only method. + * + *

    For example, a source method declared as public void foo(String text, int length) + * would return the array {"QString;","I"}. + * + * @return the type signatures for the parameters of this method, an empty array if this method has no parameters + * @see Signature + */ +String[] getParameterTypes(); +/** + * Returns the type signature of the return value of this method. + * For constructors, this returns the signature for void. + * + *

    For example, a source method declared as public String getName() + * would return "QString;". + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the type signature of the return value of this method, void for constructors + * @see Signature + */ +String getReturnType() throws JavaModelException; +/** + * Returns the signature of the method. This includes the signatures for the parameter + * types and return type, but does not include the method name or exception types. + * + *

    For example, a source method declared as public void foo(String text, int length) + * would return "(QString;I)V". + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * + * @see Signature + */ +String getSignature() throws JavaModelException; +/** + * Returns whether this method is a constructor. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * + * @return true if this method is a constructor, false otherwise + */ +boolean isConstructor() throws JavaModelException; +/** + * Returns whether this method is a main method. + * It is a main method if: + *

    + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @since 2.0 + * @return true if this method is a main method, false otherwise + */ +boolean isMainMethod() throws JavaModelException; +/** + * Returns whether this method is similar to the given method. + * Two methods are similar if: + * + * This is a handle-only method. + * + * @param method the given method + * @return true if this method is similar to the given method. + * @see Signature#getSimpleName + * @since 2.0 + */ +boolean isSimilar(IMethod method); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java new file mode 100644 index 0000000..e0e17e3 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * Common protocol for Java elements that must be opened before they can be + * navigated or modified. Opening a textual element (such as a compilation unit) + * involves opening a buffer on its contents. While open, any changes to the buffer + * can be reflected in the element's structure; + * see isConsistent and makeConsistent(IProgressMonitor). + *

    + * To reduce complexity in clients, elements are automatically opened + * by the Java model as element properties are accessed. The Java model maintains + * an LRU cache of open elements, and automatically closes elements as they + * are swapped out of the cache to make room for other elements. Elements with + * unsaved changes are never removed from the cache, and thus, if the client + * maintains many open elements with unsaved + * changes, the LRU cache can grow in size (in this case the cache is not + * bounded). However, as elements are saved, the cache will shrink back to its + * original bounded size. + *

    + *

    + * To open an element, all openable parent elements must be open. + * The Java model automatically opens parent elements, as it automatically opens elements. + * Opening an element may provide access to direct children and other descendants, + * but does not automatically open any descendents which are themselves IOpenable. + * For example, opening a compilation unit provides access to all its constituent elements, + * but opening a package fragment does not open all compilation units in the package fragment. + *

    + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface IOpenable { + +/** + * Closes this element and its buffer (if any). + * Closing an element which is not open has no effect. + * + *

    Note: although close is exposed in the API, clients are + * not expected to open and close elements - the Java model does this automatically + * as elements are accessed. + * + * @exception JavaModelException if an error occurs closing this element + */ +public void close() throws JavaModelException; +/** + * Returns the buffer opened for this element, or null + * if this element does not have a buffer. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the buffer opened for this element, or null + * if this element does not have a buffer + */ +public IBuffer getBuffer() throws JavaModelException; +/** + * Returns true if this element is open and: + *

    + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return true if this element is open and: + * + */ +boolean hasUnsavedChanges() throws JavaModelException; +/** + * Returns whether the element is consistent with its underlying resource or buffer. + * The element is consistent when opened, and is consistent if the underlying resource + * or buffer has not been modified since it was last consistent. + * + *

    NOTE: Child consistency is not considered. For example, a package fragment + * responds true when it knows about all of its + * compilation units present in its underlying folder. However, one or more of + * the compilation units could be inconsistent. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return true if the element is consistent with its underlying resource or buffer, false otherwise. + * @see IOpenable#makeConsistent + */ +boolean isConsistent() throws JavaModelException; +/** + * Returns whether this openable is open. This is a handle-only method. + * @return true if this openable is open, false otherwise + */ +boolean isOpen(); +/** + * Makes this element consistent with its underlying resource or buffer + * by updating the element's structure and properties as necessary. + * + * @param progress the given progress monitor + * @exception JavaModelException if the element is unable to access the contents + * of its underlying resource. Reasons include: + *

    + * @see IOpenable#isConsistent + */ +void makeConsistent(IProgressMonitor progress) throws JavaModelException; +/** + * Opens this element and all parent elements that are not already open. + * For compilation units, a buffer is opened on the contents of the underlying resource. + * + *

    Note: although open is exposed in the API, clients are + * not expected to open and close elements - the Java model does this automatically + * as elements are accessed. + * + * @param progress the given progress monitor + * @exception JavaModelException if an error occurs accessing the contents + * of its underlying resource. Reasons include: + *

    + */ +public void open(IProgressMonitor progress) throws JavaModelException; +/** + * Saves any changes in this element's buffer to its underlying resource + * via a workspace resource operation. This has no effect if the element has no underlying + * buffer, or if there are no unsaved changed in the buffer. + *

    + * The force parameter controls how this method deals with + * cases where the workbench is not completely in sync with the local file system. + * If false is specified, this method will only attempt + * to overwrite a corresponding file in the local file system provided + * it is in sync with the workbench. This option ensures there is no + * unintended data loss; it is the recommended setting. + * However, if true is specified, an attempt will be made + * to write a corresponding file in the local file system, + * overwriting any existing one if need be. + * In either case, if this method succeeds, the resource will be marked + * as being local (even if it wasn't before). + *

    + * As a result of this operation, the element is consistent with its underlying + * resource or buffer. + * + * @param progress the given progress monitor + * @param force it controls how this method deals with + * cases where the workbench is not completely in sync with the local file system + * @exception JavaModelException if an error occurs accessing the contents + * of its underlying resource. Reasons include: + *

    + */ +public void save(IProgressMonitor progress, boolean force) throws JavaModelException; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java new file mode 100644 index 0000000..cb37b5d --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * Common protocol for Java elements that contain other Java elements. + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface IParent { +/** + * Returns the immediate children of this element. + * Unless otherwise specified by the implementing element, + * the children are in no particular order. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @return the immediate children of this element + */ +IJavaElement[] getChildren() throws JavaModelException; +/** + * Returns whether this element has one or more immediate children. + * This is a convenience method, and may be more efficient than + * testing whether getChildren is an empty array. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + * @return true if the immediate children of this element, false otherwise + */ +boolean hasChildren() throws JavaModelException; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IProblemRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IProblemRequestor.java new file mode 100644 index 0000000..5f3fff2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IProblemRequestor.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import net.sourceforge.phpdt.core.compiler.IProblem; + +/** + * A callback interface for receiving java problem as they are discovered + * by some Java operation. + * + * @see IProblem + * @since 2.0 + */ +public interface IProblemRequestor { + + /** + * Notification of a Java problem. + * + * @param problem IProblem - The discovered Java problem. + */ + void acceptProblem(IProblem problem); + + /** + * Notification sent before starting the problem detection process. + * Typically, this would tell a problem collector to clear previously recorded problems. + */ + void beginReporting(); + + /** + * Notification sent after having completed problem detection process. + * Typically, this would tell a problem collector that no more problems should be expected in this + * iteration. + */ + void endReporting(); + + /** + * Predicate allowing the problem requestor to signal whether or not it is currently + * interested by problem reports. When answering false, problem will + * not be discovered any more until the next iteration. + * + * This predicate will be invoked once prior to each problem detection iteration. + * + * @return boolean - indicates whether the requestor is currently interested by problems. + */ + boolean isActive(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ISourceManipulation.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ISourceManipulation.java new file mode 100644 index 0000000..e829cfe --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ISourceManipulation.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * Common protocol for Java elements that support source code manipulations such + * as copy, move, rename, and delete. + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface ISourceManipulation { +/** + * Copies this element to the given container. + * + * @param container the container + * @param sibling the sibling element before which the copy should be inserted, + * or null if the copy should be inserted as the last child of + * the container + * @param rename the new name for the element, or null if the copy + * retains the name of this element + * @param replace true if any existing child in the container with + * the target name should be replaced, and false to throw an + * exception in the event of a name collision + * @param monitor a progress monitor + * @exception JavaModelException if this element could not be copied. Reasons include: + *
      + *
    • This Java element, container element, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    • A CoreException occurred while updating an underlying resource + *
    • The container is of an incompatible type (INVALID_DESTINATION) + *
    • The sibling is not a child of the given container (INVALID_SIBLING) + *
    • The new name is invalid (INVALID_NAME) + *
    • A child in the container already exists with the same name (NAME_COLLISION) + * and replace has been specified as false + *
    • The container or this element is read-only (READ_ONLY) + *
    + * + * @exception IllegalArgumentException if container is null + */ +void copy(IJavaElement container, IJavaElement sibling, String rename, boolean replace, IProgressMonitor monitor) throws JavaModelException; +/** + * Deletes this element, forcing if specified and necessary. + * + * @param force a flag controlling whether underlying resources that are not + * in sync with the local file system will be tolerated (same as the force flag + * in IResource operations). + * @param monitor a progress monitor + * @exception JavaModelException if this element could not be deleted. Reasons include: + *
      + *
    • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    • A CoreException occurred while updating an underlying resource (CORE_EXCEPTION)
    • + *
    • This element is read-only (READ_ONLY)
    • + *
    + */ +void delete(boolean force, IProgressMonitor monitor) throws JavaModelException; +/** + * Moves this element to the given container. + * + * @param container the container + * @param sibling the sibling element before which the element should be inserted, + * or null if the element should be inserted as the last child of + * the container + * @param rename the new name for the element, or null if the + * element retains its name + * @param replace true if any existing child in the container with + * the target name should be replaced, and false to throw an + * exception in the event of a name collision + * @param monitor a progress monitor + * @exception JavaModelException if this element could not be moved. Reasons include: + *
      + *
    • This Java element, container element, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    • A CoreException occurred while updating an underlying resource + *
    • The container is of an incompatible type (INVALID_DESTINATION) + *
    • The sibling is not a child of the given container (INVALID_SIBLING) + *
    • The new name is invalid (INVALID_NAME) + *
    • A child in the container already exists with the same name (NAME_COLLISION) + * and replace has been specified as false + *
    • The container or this element is read-only (READ_ONLY) + *
    + * + * @exception IllegalArgumentException if container is null + */ +void move(IJavaElement container, IJavaElement sibling, String rename, boolean replace, IProgressMonitor monitor) throws JavaModelException; +/** + * Renames this element to the given name. + * + * @param name the new name for the element + * @param replace true if any existing element with the target name + * should be replaced, and false to throw an exception in the + * event of a name collision + * @param monitor a progress monitor + * @exception JavaModelException if this element could not be renamed. Reasons include: + *
      + *
    • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    • A CoreException occurred while updating an underlying resource + *
    • The new name is invalid (INVALID_NAME) + *
    • A child in the container already exists with the same name (NAME_COLLISION) + * and replace has been specified as false + *
    • This element is read-only (READ_ONLY) + *
    + */ +void rename(String name, boolean replace, IProgressMonitor monitor) throws JavaModelException; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ISourceRange.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ISourceRange.java new file mode 100644 index 0000000..02d4da8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ISourceRange.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * A source range defines an element's source coordinates relative to + * its source buffer. + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface ISourceRange { + +/** + * Returns the number of characters of the source code for this element, + * relative to the source buffer in which this element is contained. + * + * @return the number of characters of the source code for this element, + * relative to the source buffer in which this element is contained + */ +int getLength(); +/** + * Returns the 0-based index of the first character of the source code for this element, + * relative to the source buffer in which this element is contained. + * + * @return the 0-based index of the first character of the source code for this element, + * relative to the source buffer in which this element is contained + */ +int getOffset(); +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ISourceReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ISourceReference.java new file mode 100644 index 0000000..09ef815 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/ISourceReference.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +/** + * Common protocol for Java elements that have associated source code. + * This set consists of IClassFile, ICompilationUnit, + * IPackageDeclaration, IImportDeclaration, + * IImportContainer, IType, IField, + * IMethod, and IInitializer. + * + *

    + * Note: For IClassFile, IType and other members + * derived from a binary type, the implementation returns source iff the + * element has attached source code. + *

    + *

    + * Source reference elements may be working copies if they were created from + * a compilation unit that is a working copy. + *

    + *

    + * This interface is not intended to be implemented by clients. + *

    + * + * @see IPackageFragmentRoot#attachSource + */ +public interface ISourceReference { +/** + * Returns whether this element exists in the model. + * + * @return true if this element exists in the Java model + * @since 2.0 + */ +boolean exists(); + +/** + * Returns the source code associated with this element. + * This extracts the substring from the source buffer containing this source + * element. This corresponds to the source range that would be returned by + * getSourceRange. + *

    + * For class files, this returns the source of the entire compilation unit + * associated with the class file (if there is one). + *

    + * + * @return the source code, or null if this element has no + * associated source code + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +String getSource() throws JavaModelException; +/** + * Returns the source range associated with this element. + *

    + * For class files, this returns the range of the entire compilation unit + * associated with the class file (if there is one). + *

    + * + * @return the source range, or null if this element has no + * associated source code + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource + */ +ISourceRange getSourceRange() throws JavaModelException; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IType.java new file mode 100644 index 0000000..1a69299 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IType.java @@ -0,0 +1,569 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * Represents either a source type in a compilation unit (either a top-level + * type or a member type) or a binary type in a class file. + *

    + * If a binary type cannot be parsed, its structure remains unknown. + * Use IJavaElement.isStructureKnown to determine whether this + * is the case. + *

    + *

    + * The children are of type IMember, which includes IField, + * IMethod, IInitializer and IType. + * The children are listed in the order in which they appear in the source or class file. + *

    + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface IType extends IMember, IParent { + /** + * Do code completion inside a code snippet in the context of the current type. + * + * If the type can access to his source code and the insertion position is valid, + * then completion is performed against source. Otherwise the completion is performed + * against type structure and given locals variables. + * + * @param snippet the code snippet + * @param insertion the position with in source where the snippet + * is inserted. This position must not be in comments. + * A possible value is -1, if the position is not known. + * @param position the position with in snippet where the user + * is performing code assist. + * @param localVariableTypesNames an array (possibly empty) of fully qualified + * type names of local variables visible at the current scope + * @param localVariableNames an array (possibly empty) of local variable names + * that are visible at the current scope + * @param localVariableModifiers an array (possible empty) of modifiers for + * local variables + * @param isStatic whether the current scope is in a static context + * @param requestor the completion requestor + * @since 2.0 + */ + void codeComplete( + char[] snippet, + int insertion, + int position, + char[][] localVariableTypeNames, + char[][] localVariableNames, + int[] localVariableModifiers, + boolean isStatic, + ICompletionRequestor requestor) + throws JavaModelException; + + /** + * Creates and returns a field in this type with the + * given contents. + *

    + * Optionally, the new element can be positioned before the specified + * sibling. If no sibling is specified, the element will be inserted + * as the last field declaration in this type.

    + * + *

    It is possible that a field with the same name already exists in this type. + * The value of the force parameter effects the resolution of + * such a conflict:

      + *
    • true - in this case the field is created with the new contents
    • + *
    • false - in this case a JavaModelException is thrown
    • + *

    + * + * @param contents the given contents + * @param sibling the given sibling + * @param force a flag in case the same name already exists in this type + * @param monitor the given progress monitor + * @exception JavaModelException if the element could not be created. Reasons include: + *
      + *
    • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    • A CoreException occurred while updating an underlying resource + *
    • The specified sibling is not a child of this type (INVALID_SIBLING) + *
    • The contents could not be recognized as a field declaration (INVALID_CONTENTS) + *
    • This type is read-only (binary) (READ_ONLY) + *
    • There was a naming collision with an existing field (NAME_COLLISION) + *
    + * @return a field in this type with the given contents + */ + IField createField(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) + throws JavaModelException; + + /** + * Creates and returns a static initializer in this type with the + * given contents. + *

    + * Optionally, the new element can be positioned before the specified + * sibling. If no sibling is specified, the new initializer is positioned + * after the last existing initializer declaration, or as the first member + * in the type if there are no initializers.

    + * + * @param contents the given contents + * @param sibling the given sibling + * @param monitor the given progress monitor + * @exception JavaModelException if the element could not be created. Reasons include: + *
      + *
    • This element does not exist + *
    • A CoreException occurred while updating an underlying resource + *
    • The specified sibling is not a child of this type (INVALID_SIBLING) + *
    • The contents could not be recognized as an initializer declaration (INVALID_CONTENTS) + *
    • This type is read-only (binary) (READ_ONLY) + *
    + * @return a static initializer in this type with the given contents + */ + IInitializer createInitializer(String contents, IJavaElement sibling, IProgressMonitor monitor) + throws JavaModelException; + + /** + * Creates and returns a method or constructor in this type with the + * given contents. + *

    + * Optionally, the new element can be positioned before the specified + * sibling. If no sibling is specified, the element will be appended + * to this type. + * + *

    It is possible that a method with the same signature already exists in this type. + * The value of the force parameter effects the resolution of + * such a conflict:

      + *
    • true - in this case the method is created with the new contents
    • + *
    • false - in this case a JavaModelException is thrown
    • + *

    + * + * @param contents the given contents + * @param sibling the given sibling + * @param force a flag in case the same name already exists in this type + * @param monitor the given progress monitor + * @exception JavaModelException if the element could not be created. Reasons include: + *
      + *
    • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    • A CoreException occurred while updating an underlying resource + *
    • The specified sibling is not a child of this type (INVALID_SIBLING) + *
    • The contents could not be recognized as a method or constructor + * declaration (INVALID_CONTENTS) + *
    • This type is read-only (binary) (READ_ONLY) + *
    • There was a naming collision with an existing method (NAME_COLLISION) + *
    + * @return a method or constructor in this type with the given contents + */ + IMethod createMethod(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) + throws JavaModelException; + + /** + * Creates and returns a type in this type with the + * given contents. + *

    + * Optionally, the new type can be positioned before the specified + * sibling. If no sibling is specified, the type will be appended + * to this type. + * + *

    It is possible that a type with the same name already exists in this type. + * The value of the force parameter effects the resolution of + * such a conflict:

      + *
    • true - in this case the type is created with the new contents
    • + *
    • false - in this case a JavaModelException is thrown
    • + *

    + * + * @param contents the given contents + * @param sibling the given sibling + * @param force a flag in case the same name already exists in this type + * @param monitor the given progress monitor + * @exception JavaModelException if the element could not be created. Reasons include: + *
      + *
    • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    • A CoreException occurred while updating an underlying resource + *
    • The specified sibling is not a child of this type (INVALID_SIBLING) + *
    • The contents could not be recognized as a type declaration (INVALID_CONTENTS) + *
    • This type is read-only (binary) (READ_ONLY) + *
    • There was a naming collision with an existing field (NAME_COLLISION) + *
    + * @return a type in this type with the given contents + */ + IType createType(String contents, IJavaElement sibling, boolean force, IProgressMonitor monitor) + throws JavaModelException; + + /** + * Finds the methods in this type that correspond to + * the given method. + * A method m1 corresponds to another method m2 if: + *
      + *
    • m1 has the same element name as m2. + *
    • m1 has the same number of arguments as m2 and + * the simple names of the argument types must be equals. + *
    • m1 exists. + *
    + * @param method the given method + * @return the found method or null if no such methods can be found. + * + * @since 2.0 + */ + IMethod[] findMethods(IMethod method); + + /** + * Returns the simple name of this type, unqualified by package or enclosing type. + * This is a handle-only method. + * + * @return the simple name of this type + */ + String getElementName(); + + /** + * Returns the field with the specified name + * in this type (for example, "bar"). + * This is a handle-only method. The field may or may not exist. + * + * @param name the given name + * @return the field with the specified name in this type + */ + IField getField(String name); + + /** + * Returns the fields declared by this type. + * If this is a source type, the results are listed in the order + * in which they appear in the source, otherwise, the results are + * in no particular order. For binary types, this includes synthetic fields. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the fields declared by this type + */ + IField[] getFields() throws JavaModelException; + + /** + * Returns the fully qualified name of this type, + * including qualification for any containing types and packages. + * This is the name of the package, followed by '.', + * followed by the type-qualified name. + * This is a handle-only method. + * + * @see IType#getTypeQualifiedName() + * @return the fully qualified name of this type + */ + String getFullyQualifiedName(); + + /** + * Returns the fully qualified name of this type, + * including qualification for any containing types and packages. + * This is the name of the package, followed by '.', + * followed by the type-qualified name using the enclosingTypeSeparator. + * + * For example: + *
      + *
    • the fully qualified name of a class B defined as a member of a class A in a compilation unit A.java + * in a package x.y using the '.' separator is "x.y.A.B"
    • + *
    • the fully qualified name of a class B defined as a member of a class A in a compilation unit A.java + * in a package x.y using the '$' separator is "x.y.A$B"
    • + *
    • the fully qualified name of a binary type whose class file is x/y/A$B.class + * using the '.' separator is "x.y.A.B"
    • + *
    • the fully qualified name of a binary type whose class file is x/y/A$B.class + * using the '$' separator is "x.y.A$B"
    • + *
    • the fully qualified name of an anonymous binary type whose class file is x/y/A$1.class + * using the '.' separator is "x.y.A$1"
    • + *
    + * + * This is a handle-only method. + * + * @param enclosingTypeSeparator the given enclosing type separator + * @return the fully qualified name of this type, including qualification for any containing types and packages + * @see IType#getTypeQualifiedName(char) + * @since 2.0 + */ + String getFullyQualifiedName(char enclosingTypeSeparator); + + /** + * Returns the initializer with the specified position relative to + * the order they are defined in the source. + * Numbering starts at 1 (i.e. the first occurrence is occurrence 1, not occurrence 0). + * This is a handle-only method. The initializer may or may not be present. + * + * @param occurrenceCount the specified position + * @return the initializer with the specified position relative to the order they are defined in the source + */ + IInitializer getInitializer(int occurrenceCount); + + /** + * Returns the initializers declared by this type. + * For binary types this is an empty collection. + * If this is a source type, the results are listed in the order + * in which they appear in the source. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the initializers declared by this type + */ + IInitializer[] getInitializers() throws JavaModelException; + + /** + * Returns the method with the specified name and parameter types + * in this type (for example, "foo", {"I", "QString;"}). To get the + * handle for a constructor, the name specified must be the simple + * name of the enclosing type. + * This is a handle-only method. The method may or may not be present. + * + * @param name the given name + * @param parameterTypeSignatures the given parameter types + * @return the method with the specified name and parameter types in this type + */ + IMethod getMethod(String name, String[] parameterTypeSignatures); + + /** + * Returns the methods and constructors declared by this type. + * For binary types, this may include the special <clinit>; method + * and synthetic methods. + * If this is a source type, the results are listed in the order + * in which they appear in the source, otherwise, the results are + * in no particular order. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the methods and constructors declared by this type + */ + IMethod[] getMethods() throws JavaModelException; + + /** + * Returns the package fragment in which this element is defined. + * This is a handle-only method. + * + * @return the package fragment in which this element is defined + */ + //IPackageFragment getPackageFragment(); + + /** + * Returns the name of this type's superclass, or null + * for source types that do not specify a superclass. + * For interfaces, the superclass name is always "java.lang.Object". + * For source types, the name as declared is returned, for binary types, + * the resolved, qualified name is returned. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the name of this type's superclass, or null for source types that do not specify a superclass + */ + String getSuperclassName() throws JavaModelException; + + /** + * Returns the names of interfaces that this type implements or extends, + * in the order in which they are listed in the source. + * For classes, this gives the interfaces that this class implements. + * For interfaces, this gives the interfaces that this interface extends. + * An empty collection is returned if this type does not implement or + * extend any interfaces. For source types, simples name are returned, + * for binary types, qualified names are returned. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the names of interfaces that this type implements or extends, in the order in which they are listed in the source, + * an empty collection if none + */ + String[] getSuperInterfaceNames() throws JavaModelException; + + /** + * Returns the member type declared in this type with the given simple name. + * This is a handle-only method. The type may or may not exist. + * + * @param the given simple name + * @return the member type declared in this type with the given simple name + */ + IType getType(String name); + + /** + * Returns the type-qualified name of this type, + * including qualification for any enclosing types, + * but not including package qualification. + * For source types, this consists of the simple names of + * any enclosing types, separated by "$", followed by the simple name of this type. + * For binary types, this is the name of the class file without the ".class" suffix. + * This is a handle-only method. + * + * @return the type-qualified name of this type + */ + String getTypeQualifiedName(); + + /** + * Returns the type-qualified name of this type, + * including qualification for any enclosing types, + * but not including package qualification. + * This consists of the simple names of any enclosing types, + * separated by the enclosingTypeSeparator, + * followed by the simple name of this type. + * + * For example: + *
      + *
    • the type qualified name of a class B defined as a member of a class A + * using the '.' separator is "A.B"
    • + *
    • the type qualified name of a class B defined as a member of a class A + * using the '$' separator is "A$B"
    • + *
    • the type qualified name of a binary type whose class file is A$B.class + * using the '.' separator is "A.B"
    • + *
    • the type qualified name of a binary type whose class file is A$B.class + * using the '$' separator is "A$B"
    • + *
    • the type qualified name of an anonymous binary type whose class file is A$1.class + * using the '.' separator is "A$1"
    • + *
    + * + * This is a handle-only method. + * + * @param enclosingTypeSeparator the specified enclosing type separator + * @return the type-qualified name of this type + * @since 2.0 + */ + String getTypeQualifiedName(char enclosingTypeSeparator); + + /** + * Returns the immediate member types declared by this type. + * The results are listed in the order in which they appear in the source or class file. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return the immediate member types declared by this type + */ + IType[] getTypes() throws JavaModelException; + + /** + * Returns whether this type represents an anonymous type. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return true if this type represents an anonymous type, false otherwise + * @since 2.0 + */ + boolean isAnonymous() throws JavaModelException; + + /** + * Returns whether this type represents a class. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return true if this type represents a class, false otherwise + */ + boolean isClass() throws JavaModelException; + + /** + * Returns whether this type represents an interface. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return true if this type represents an interface, false otherwise + */ + boolean isInterface() throws JavaModelException; + + /** + * Returns whether this type represents a local type. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return true if this type represents a local type, false otherwise + * @since 2.0 + */ + boolean isLocal() throws JavaModelException; + + /** + * Returns whether this type represents a member type. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return true if this type represents a member type, false otherwise + * @since 2.0 + */ + boolean isMember() throws JavaModelException; + + /** + * Creates and returns a type hierarchy for this type containing + * this type and all of its supertypes. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @param monitor the given progress monitor + * @return a type hierarchy for this type containing this type and all of its supertypes + */ + //ITypeHierarchy newSupertypeHierarchy(IProgressMonitor monitor) throws JavaModelException; + + /** + * Creates and returns a type hierarchy for this type containing + * this type and all of its supertypes, considering types in the given + * working copies. In other words, the list of working copies will take + * precedence over their original compilation units in the workspace. + *

    + * Note that passing an empty working copy will be as if the original compilation + * unit had been deleted. + * + * @param workingCopies the working copies that take precedence over their original compilation units + * @param monitor the given progress monitor + * @return a type hierarchy for this type containing this type and all of its supertypes + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @since 2.0 + */ +// ITypeHierarchy newSupertypeHierarchy(IWorkingCopy[] workingCopies, IProgressMonitor monitor) +// throws JavaModelException; +// + /** + * Creates and returns a type hierarchy for this type containing + * this type, all of its supertypes, and all its subtypes in the workspace. + * + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @param monitor the given progress monitor + * @return a type hierarchy for this type containing + * this type, all of its supertypes, and all its subtypes in the workspace + */ +// ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor) throws JavaModelException; + + /** + * Creates and returns a type hierarchy for this type containing + * this type, all of its supertypes, and all its subtypes in the workspace, + * considering types in the given working copies. In other words, the list of working + * copies that will take precedence over their original compilation units in the workspace. + *

    + * Note that passing an empty working copy will be as if the original compilation + * unit had been deleted. + * + * @param workingCopies the working copies that take precedence over their original compilation units + * @param monitor the given progress monitor + * @return a type hierarchy for this type containing + * this type, all of its supertypes, and all its subtypes in the workspace + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @since 2.0 + */ + // ITypeHierarchy newTypeHierarchy(IWorkingCopy[] workingCopies, IProgressMonitor monitor) throws JavaModelException; + + /** + * Creates and returns a type hierarchy for this type containing + * this type, all of its supertypes, and all its subtypes + * in the context of the given project. + * + * @param project the given project + * @param monitor the given progress monitor + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @return a type hierarchy for this type containing + * this type, all of its supertypes, and all its subtypes + * in the context of the given project + */ +// ITypeHierarchy newTypeHierarchy(IJavaProject project, IProgressMonitor monitor) throws JavaModelException; + + /** + * Resolves the given type name within the context of this type (depending on the type hierarchy + * and its imports). Multiple answers might be found in case there are ambiguous matches. + * + * Each matching type name is decomposed as an array of two strings, the first denoting the package + * name (dot-separated) and the second being the type name. + * Returns null if unable to find any matching type. + * + * For example, resolution of "Object" would typically return + * {{"java.lang", "Object"}}. + * + * @param typeName the given type name + * @exception JavaModelException if code resolve could not be performed. + * @return the resolved type names or null if unable to find any matching type + */ + String[][] resolveType(String typeName) throws JavaModelException; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IWorkingCopy.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IWorkingCopy.java new file mode 100644 index 0000000..da5c9d5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IWorkingCopy.java @@ -0,0 +1,349 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API + * IBM Corporation, 2002/03/01- added notion of shared working copy + * IBM Corporation, 2002/26/01- added notion of IProblemRequestor + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * Common protocol for Java elements that support working copies. + *

    + * A working copy of a Java element acts just like a regular element (handle), + * except it is not attached to an underlying resource. A working copy is not + * visible to the rest of the Java model. Changes in a working copy's + * buffer are not realized in a resource. To bring the Java model up-to-date with a working + * copy's contents, an explicit commit must be performed on the working copy. + * Other operations performed on a working copy update the + * contents of the working copy's buffer but do not commit the contents + * of the working copy. + *

    + *

    + * Note: The contents of a working copy is determined when a working + * copy is created, based on the current content of the element the working + * copy is created from. If a working copy is an IOpenable and is explicitly + * closed, the working copy's buffer will be thrown away. However, clients should not + * explicitly open and close working copies. + *

    + *

    + * The client that creates a working copy is responsible for + * destroying the working copy. The Java model will never automatically + * destroy or close a working copy. (Note that destroying a working copy + * does not commit it to the model, it only frees up the memory occupied by + * the element). After a working copy is destroyed, the working copy cannot + * be accessed again. Non-handle methods will throw a + * JavaModelException indicating the Java element does not exist. + *

    + *

    + * A working copy cannot be created from another working copy. + * Calling getWorkingCopy on a working copy returns the receiver. + *

    + *

    + * This interface is not intended to be implemented by clients. + *

    + */ +public interface IWorkingCopy { + + /** + * Commits the contents of this working copy to its original element + * and underlying resource, bringing the Java model up-to-date with + * the current contents of the working copy. + * + *

    It is possible that the contents of the original resource have changed + * since this working copy was created, in which case there is an update conflict. + * The value of the force parameter effects the resolution of + * such a conflict:

      + *
    • true - in this case the contents of this working copy are applied to + * the underlying resource even though this working copy was created before + * a subsequent change in the resource
    • + *
    • false - in this case a JavaModelException is thrown
    • + *
    + * + * @param force a flag to handle the cases when the contents of the original resource have changed + * since this working copy was created + * @param monitor the given progress monitor + * @exception JavaModelException if this working copy could not commit. Reasons include: + *
      + *
    • The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    • A CoreException occurred while updating an underlying resource + *
    • This element is not a working copy (INVALID_ELEMENT_TYPES) + *
    • A update conflict (described above) (UPDATE_CONFLICT) + *
    + */ + void commit(boolean force, IProgressMonitor monitor) throws JavaModelException; + + /** + * Destroys this working copy, closing its buffer and discarding + * its structure. Subsequent attempts to access non-handle information + * for this working copy will result in IJavaModelExceptions. Has + * no effect if this element is not a working copy. + *

    + * If this working copy is shared, it is destroyed only when the number of calls to + * destroy() is the same as the number of calls to + * getSharedWorkingCopy(IProgressMonitor, IBufferFactory). + * A REMOVED IJavaElementDelta is then reported on this working copy. + */ + void destroy(); + + /** + * Finds the shared working copy for this element, given a IBuffer factory. + * If no working copy has been created for this element associated with this + * buffer factory, returns null. + *

    + * Users of this method must not destroy the resulting working copy. + * + * @param bufferFactory the given IBuffer factory + * @return the found shared working copy for this element, null if none + * @see IBufferFactory + * @since 2.0 + */ + IJavaElement findSharedWorkingCopy(IBufferFactory bufferFactory); + + /** + * Returns the original element the specified working copy element was created from, + * or null if this is not a working copy element. This is a handle + * only method, the returned element may or may not exist. + * + * @return the original element the specified working copy element was created from, + * or null if this is not a working copy element + */ + IJavaElement getOriginal(IJavaElement workingCopyElement); + + /** + * Returns the original element this working copy was created from, + * or null if this is not a working copy. + * + * @return the original element this working copy was created from, + * or null if this is not a working copy + */ + IJavaElement getOriginalElement(); + + /** + * Finds the elements in this compilation unit that correspond to + * the given element. + * An element A corresponds to an element B if: + *

      + *
    • A has the same element name as B. + *
    • If A is a method, A must have the same number of arguments as + * B and the simple names of the argument types must be equals. + *
    • The parent of A corresponds to the parent of B recursively up to + * their respective compilation units. + *
    • A exists. + *
    + * Returns null if no such java elements can be found + * or if the given element is not included in a compilation unit. + * + * @param element the given element + * @return the found elements in this compilation unit that correspond to the given element + * @since 2.0 + */ + IJavaElement[] findElements(IJavaElement element); + + /** + * Finds the primary type of this compilation unit (i.e. the type with the same name as the + * compilation unit), or null if no such a type exists. + * + * @return the found primary type of this compilation unit, or null if no such a type exists + * @since 2.0 + */ + IType findPrimaryType(); + + /** + * Returns a shared working copy on this element using the given factory to create + * the buffer, or this element if this element is already a working copy. + * This API can only answer an already existing working copy if it is based on the same + * original compilation unit AND was using the same buffer factory (i.e. as defined by Object#equals). + *

    + * The life time of a shared working copy is as follows: + *

      + *
    • The first call to getSharedWorkingCopy(...) creates a new working copy for this + * element
    • + *
    • Subsequent calls increment an internal counter.
    • + *
    • A call to destroy() decrements the internal counter.
    • + *
    • When this counter is 0, the working copy is destroyed. + *
    + * So users of this method must destroy exactly once the working copy. + *

    + * Note that the buffer factory will be used for the life time of this working copy, i.e. if the + * working copy is closed then reopened, this factory will be used. + * The buffer will be automatically initialized with the original's compilation unit content + * upon creation. + *

    + * When the shared working copy instance is created, an ADDED IJavaElementDelta is reported on this + * working copy. + * + * @param monitor a progress monitor used to report progress while opening this compilation unit + * or null if no progress should be reported + * @param factory the factory that creates a buffer that is used to get the content of the working copy + * or null if the internal factory should be used + * @param problemRequestor a requestor which will get notified of problems detected during + * reconciling as they are discovered. The requestor can be set to null indicating + * that the client is not interested in problems. + * @exception JavaModelException if the contents of this element can + * not be determined. Reasons include: + *

      + *
    • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    + * @return a shared working copy on this element using the given factory to create + * the buffer, or this element if this element is already a working copy + * @see IBufferFactory + * @see IProblemRequestor + * @since 2.0 + */ + IJavaElement getSharedWorkingCopy( + IProgressMonitor monitor, + IBufferFactory factory, + IProblemRequestor problemRequestor) + throws JavaModelException; + + /** + * Returns a new working copy of this element if this element is not + * a working copy, or this element if this element is already a working copy. + * + * Note: if intending to share a working copy amongst several clients, then + * #getSharedWorkingCopy should be used instead. + * + * @exception JavaModelException if the contents of this element can + * not be determined. Reasons include: + *
      + *
    • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    + * @return a new working copy of this element if this element is not + * a working copy, or this element if this element is already a working copy + */ + IJavaElement getWorkingCopy() throws JavaModelException; + + /** + * Returns a new working copy of this element using the given factory to create + * the buffer, or this element if this element is already a working copy. + * Note that this factory will be used for the life time of this working copy, i.e. if the + * working copy is closed then reopened, this factory will be reused. + * The buffer will be automatically initialized with the original's compilation unit content + * upon creation. + * + * Note: if intending to share a working copy amongst several clients, then + * #getSharedWorkingCopy should be used instead. + * + * @param monitor a progress monitor used to report progress while opening this compilation unit + * or null if no progress should be reported + * @param factory the factory that creates a buffer that is used to get the content of the working copy + * or null if the internal factory should be used + * @param problemRequestor a requestor which will get notified of problems detected during + * reconciling as they are discovered. The requestor can be set to null indicating + * that the client is not interested in problems. + * @exception JavaModelException if the contents of this element can + * not be determined. Reasons include: + *
      + *
    • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    + * @return a new working copy of this element using the given factory to create + * the buffer, or this element if this element is already a working copy + * @since 2.0 + */ + IJavaElement getWorkingCopy( + IProgressMonitor monitor, + IBufferFactory factory, + IProblemRequestor problemRequestor) + throws JavaModelException; + + /** + * Returns whether this working copy's original element's content + * has not changed since the inception of this working copy. + * + * @return true if this working copy's original element's content + * has not changed since the inception of this working copy, false otherwise + */ + boolean isBasedOn(IResource resource); + + /** + * Returns whether this element is a working copy. + * + * @return true if this element is a working copy, false otherwise + */ + boolean isWorkingCopy(); + + /** + * Reconciles the contents of this working copy. + * It performs the reconciliation by locally caching the contents of + * the working copy, updating the contents, then creating a delta + * over the cached contents and the new contents, and finally firing + * this delta. + *

    + * If the working copy hasn't changed, then no problem will be detected, + * this is equivalent to IWorkingCopy#reconcile(false, null). + *

    + * Compilation problems found in the new contents are notified through the + * IProblemRequestor interface which was passed at + * creation, and no longer as transient markers. Therefore this API will + * return null. + *

    + * Note: It has been assumed that added inner types should + * not generate change deltas. The implementation has been + * modified to reflect this assumption. + * + * @exception JavaModelException if the contents of the original element + * cannot be accessed. Reasons include: + *

      + *
    • The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    + * @return null + */ + IMarker[] reconcile() throws JavaModelException; + + /** + * Reconciles the contents of this working copy. + * It performs the reconciliation by locally caching the contents of + * the working copy, updating the contents, then creating a delta + * over the cached contents and the new contents, and finally firing + * this delta. + *

    + * The boolean argument allows to force problem detection even if the + * working copy is already consistent. + *

    + * Compilation problems found in the new contents are notified through the + * IProblemRequestor interface which was passed at + * creation, and no longer as transient markers. Therefore this API answers + * nothing. + *

    + * Note: It has been assumed that added inner types should + * not generate change deltas. The implementation has been + * modified to reflect this assumption. + * + * @param forceProblemDetection boolean indicating whether problem should be recomputed + * even if the source hasn't changed. + * @param monitor a progress monitor + * @exception JavaModelException if the contents of the original element + * cannot be accessed. Reasons include: + *

      + *
    • The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    + * @since 2.0 + */ + void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws JavaModelException; + + /** + * Restores the contents of this working copy to the current contents of + * this working copy's original element. Has no effect if this element + * is not a working copy. + * + *

    Note: This is the inverse of committing the content of the + * working copy to the original element with commit(boolean, IProgressMonitor). + * + * @exception JavaModelException if the contents of the original element + * cannot be accessed. Reasons include: + *

      + *
    • The original Java element does not exist (ELEMENT_DOES_NOT_EXIST)
    • + *
    + */ + void restore() throws JavaModelException; +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java new file mode 100644 index 0000000..7417c88 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; + +import net.sourceforge.phpdt.internal.core.JavaModelStatus; + +/** + * A checked exception representing a failure in the Java model. + * Java model exceptions contain a Java-specific status object describing the + * cause of the exception. + *

    + * This class is not intended to be subclassed by clients. Instances of this + * class are automatically created by the Java model when problems arise, so + * there is generally no need for clients to create instances. + *

    + * + * @see IJavaModelStatus + * @see IJavaModelStatusConstants + */ +public class JavaModelException extends CoreException { + CoreException nestedCoreException; +/** + * Creates a Java model exception that wrappers the given Throwable. + * The exception contains a Java-specific status object with severity + * IStatus.ERROR and the given status code. + * + * @param exception the Throwable + * @param code one of the Java-specific status codes declared in + * IJavaModelStatusConstants + * @see IJavaModelStatusConstants + * @see org.eclipse.core.runtime.IStatus#ERROR + */ +public JavaModelException(Throwable e, int code) { + this(new JavaModelStatus(code, e)); +} +/** + * Creates a Java model exception for the given CoreException. + * Equivalent to + * JavaModelException(exception,IJavaModelStatusConstants.CORE_EXCEPTION. + * + * @param exception the CoreException + */ +public JavaModelException(CoreException exception) { + super(exception.getStatus()); + this.nestedCoreException = exception; +} +/** + * Creates a Java model exception for the given Java-specific status object. + * + * @param status the Java-specific status object + */ +public JavaModelException(IJavaModelStatus status) { + super(status); +} +/** + * Returns the underlying Throwable that caused the failure. + * + * @return the wrappered Throwable, or null if the + * direct case of the failure was at the Java model layer + */ +public Throwable getException() { + if (this.nestedCoreException == null) { + return getStatus().getException(); + } else { + return this.nestedCoreException; + } +} +/** + * Returns the Java model status object for this exception. + * Equivalent to (IJavaModelStatus) getStatus(). + * + * @return a status object + */ +public IJavaModelStatus getJavaModelStatus() { + IStatus status = this.getStatus(); + if (status instanceof IJavaModelStatus) { + return (IJavaModelStatus)status; + } else { + // A regular IStatus is created only in the case of a CoreException. + // See bug 13492 Should handle JavaModelExceptions that contains CoreException more gracefully + return new JavaModelStatus(this.nestedCoreException); + } +} +/** + * Returns whether this exception indicates that a Java model element does not + * exist. Such exceptions have a status with a code of + * IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST. + * This is a convenience method. + * + * @return true if this exception indicates that a Java model + * element does not exist + * @see IJavaModelStatus#isDoesNotExist + * @see IJavaModelStatusConstants#ELEMENT_DOES_NOT_EXIST + */ +public boolean isDoesNotExist() { + IJavaModelStatus javaModelStatus = getJavaModelStatus(); + return javaModelStatus != null && javaModelStatus.isDoesNotExist(); +} +/** + * Returns a printable representation of this exception suitable for debugging + * purposes only. + */ +public String toString() { + StringBuffer buffer= new StringBuffer(); + buffer.append("Java Model Exception: "); //$NON-NLS-1$ + if (getException() != null) { + if (getException() instanceof CoreException) { + CoreException c= (CoreException)getException(); + buffer.append("Core Exception [code "); //$NON-NLS-1$ + buffer.append(c.getStatus().getCode()); + buffer.append("] "); //$NON-NLS-1$ + buffer.append(c.getStatus().getMessage()); + } else { + buffer.append(getException().toString()); + } + } else { + buffer.append(getStatus().toString()); + } + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/Signature.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/Signature.java new file mode 100644 index 0000000..18d3336 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/Signature.java @@ -0,0 +1,1384 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.core; + +import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.parser.Scanner; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +/** + * Provides methods for encoding and decoding type and method signature strings. + *

    + * The syntax for a type signature is: + *

    + * typeSignature ::=
    + *     "B"  // byte
    + *   | "C"  // char
    + *   | "D"  // double
    + *   | "F"  // float
    + *   | "I"  // int
    + *   | "J"  // long
    + *   | "S"  // short
    + *   | "V"  // void
    + *   | "Z"  // boolean
    + *   | "L" + binaryTypeName + ";"  // resolved named type (i.e., in compiled code)
    + *   | "Q" + sourceTypeName + ";"  // unresolved named type (i.e., in source code)
    + *   | "[" + typeSignature  // array of type denoted by typeSignature
    + * 
    + *

    + *

    + * Examples: + *

      + *
    • "[[I" denotes int[][]
    • + *
    • "Ljava.lang.String;" denotes java.lang.String in compiled code
    • + *
    • "QString" denotes String in source code
    • + *
    • "Qjava.lang.String" denotes java.lang.String in source code
    • + *
    • "[QString" denotes String[] in source code
    • + *
    + *

    + *

    + * The syntax for a method signature is: + *

    + * methodSignature ::= "(" + paramTypeSignature* + ")" + returnTypeSignature
    + * paramTypeSignature ::= typeSignature
    + * returnTypeSignature ::= typeSignature
    + * 
    + *

    + * Examples: + *

      + *
    • "()I" denotes int foo()
    • + *
    • "([Ljava.lang.String;)V" denotes void foo(java.lang.String[]) in compiled code
    • + *
    • "(QString;)QObject;" denotes Object foo(String) in source code
    • + *
    + *

    + *

    + * This class provides static methods and constants only; it is not intended to be + * instantiated or subclassed by clients. + *

    + */ +public final class Signature { + + /** + * Character constant indicating the primitive type boolean in a signature. + * Value is 'Z'. + */ + public static final char C_BOOLEAN = 'Z'; + + /** + * Character constant indicating the primitive type byte in a signature. + * Value is 'B'. + */ + public static final char C_BYTE = 'B'; + + /** + * Character constant indicating the primitive type char in a signature. + * Value is 'C'. + */ + public static final char C_CHAR = 'C'; + + /** + * Character constant indicating the primitive type double in a signature. + * Value is 'D'. + */ + public static final char C_DOUBLE = 'D'; + + /** + * Character constant indicating the primitive type float in a signature. + * Value is 'F'. + */ + public static final char C_FLOAT = 'F'; + + /** + * Character constant indicating the primitive type int in a signature. + * Value is 'I'. + */ + public static final char C_INT = 'I'; + + /** + * Character constant indicating the semicolon in a signature. + * Value is ';'. + */ + public static final char C_SEMICOLON = ';'; + + /** + * Character constant indicating the primitive type long in a signature. + * Value is 'J'. + */ + public static final char C_LONG = 'J'; + + /** + * Character constant indicating the primitive type short in a signature. + * Value is 'S'. + */ + public static final char C_SHORT = 'S'; + + /** + * Character constant indicating result type void in a signature. + * Value is 'V'. + */ + public static final char C_VOID = 'V'; + + /** + * Character constant indicating the dot in a signature. + * Value is '.'. + */ + public static final char C_DOT = '.'; + + /** + * Character constant indicating the dollar in a signature. + * Value is '$'. + */ + public static final char C_DOLLAR = '$'; + + /** + * Character constant indicating an array type in a signature. + * Value is '['. + */ + public static final char C_ARRAY = '['; + + /** + * Character constant indicating the start of a resolved, named type in a + * signature. Value is 'L'. + */ + public static final char C_RESOLVED = 'L'; + + /** + * Character constant indicating the start of an unresolved, named type in a + * signature. Value is 'Q'. + */ + public static final char C_UNRESOLVED = 'Q'; + + /** + * Character constant indicating the end of a named type in a signature. + * Value is ';'. + */ + public static final char C_NAME_END = ';'; + + /** + * Character constant indicating the start of a parameter type list in a + * signature. Value is '('. + */ + public static final char C_PARAM_START = '('; + + /** + * Character constant indicating the end of a parameter type list in a + * signature. Value is ')'. + */ + public static final char C_PARAM_END = ')'; + + /** + * String constant for the signature of the primitive type boolean. + * Value is "Z". + */ + public static final String SIG_BOOLEAN = "Z"; //$NON-NLS-1$ + + /** + * String constant for the signature of the primitive type byte. + * Value is "B". + */ + public static final String SIG_BYTE = "B"; //$NON-NLS-1$ + + /** + * String constant for the signature of the primitive type char. + * Value is "C". + */ + public static final String SIG_CHAR = "C"; //$NON-NLS-1$ + + /** + * String constant for the signature of the primitive type double. + * Value is "D". + */ + public static final String SIG_DOUBLE = "D"; //$NON-NLS-1$ + + /** + * String constant for the signature of the primitive type float. + * Value is "F". + */ + public static final String SIG_FLOAT = "F"; //$NON-NLS-1$ + + /** + * String constant for the signature of the primitive type int. + * Value is "I". + */ + public static final String SIG_INT = "I"; //$NON-NLS-1$ + + /** + * String constant for the signature of the primitive type long. + * Value is "J". + */ + public static final String SIG_LONG = "J"; //$NON-NLS-1$ + + /** + * String constant for the signature of the primitive type short. + * Value is "S". + */ + public static final String SIG_SHORT = "S"; //$NON-NLS-1$ + + /** String constant for the signature of result type void. + * Value is "V". + */ + public static final String SIG_VOID = "V"; //$NON-NLS-1$ + + private static final char[] NO_CHAR = new char[0]; + private static final char[][] NO_CHAR_CHAR = new char[0][]; + private static final char[] BOOLEAN = {'b', 'o', 'o', 'l', 'e', 'a', 'n'}; + private static final char[] BYTE = {'b', 'y', 't', 'e'}; + private static final char[] CHAR = {'c', 'h', 'a', 'r'}; + private static final char[] DOUBLE = {'d', 'o', 'u', 'b', 'l', 'e'}; + private static final char[] FLOAT = {'f', 'l', 'o', 'a', 't'}; + private static final char[] INT = {'i', 'n', 't'}; + private static final char[] LONG = {'l', 'o', 'n', 'g'}; + private static final char[] SHORT = {'s', 'h', 'o', 'r', 't'}; + private static final char[] VOID = {'v', 'o', 'i', 'd'}; + + +/** + * Not instantiable. + */ +private Signature() {} + +private static long copyType(char[] signature, int sigPos, char[] dest, int index, boolean fullyQualifyTypeNames) { + int arrayCount = 0; + loop: while (true) { + switch (signature[sigPos++]) { + case C_ARRAY : + arrayCount++; + break; + case C_BOOLEAN : + int length = BOOLEAN.length; + System.arraycopy(BOOLEAN, 0, dest, index, length); + index += length; + break loop; + case C_BYTE : + length = BYTE.length; + System.arraycopy(BYTE, 0, dest, index, length); + index += length; + break loop; + case C_CHAR : + length = CHAR.length; + System.arraycopy(CHAR, 0, dest, index, length); + index += length; + break loop; + case C_DOUBLE : + length = DOUBLE.length; + System.arraycopy(DOUBLE, 0, dest, index, length); + index += length; + break loop; + case C_FLOAT : + length = FLOAT.length; + System.arraycopy(FLOAT, 0, dest, index, length); + index += length; + break loop; + case C_INT : + length = INT.length; + System.arraycopy(INT, 0, dest, index, length); + index += length; + break loop; + case C_LONG : + length = LONG.length; + System.arraycopy(LONG, 0, dest, index, length); + index += length; + break loop; + case C_SHORT : + length = SHORT.length; + System.arraycopy(SHORT, 0, dest, index, length); + index += length; + break loop; + case C_VOID : + length = VOID.length; + System.arraycopy(VOID, 0, dest, index, length); + index += length; + break loop; + case C_RESOLVED : + case C_UNRESOLVED : + int end = CharOperation.indexOf(C_SEMICOLON, signature, sigPos); + if (end == -1) throw new IllegalArgumentException(); + int start; + if (fullyQualifyTypeNames) { + start = sigPos; + } else { + start = CharOperation.lastIndexOf(C_DOT, signature, sigPos, end)+1; + if (start == 0) start = sigPos; + } + length = end-start; + System.arraycopy(signature, start, dest, index, length); + sigPos = end+1; + index += length; + break loop; + } + } + while (arrayCount-- > 0) { + dest[index++] = '['; + dest[index++] = ']'; + } + return (((long) index) << 32) + sigPos; +} +/** + * Creates a new type signature with the given amount of array nesting added + * to the given type signature. + * + * @param typeSignature the type signature + * @param arrayCount the desired number of levels of array nesting + * @return the encoded array type signature + * + * @since 2.0 + */ +public static char[] createArraySignature(char[] typeSignature, int arrayCount) { + if (arrayCount == 0) return typeSignature; + int sigLength = typeSignature.length; + char[] result = new char[arrayCount + sigLength]; + for (int i = 0; i < arrayCount; i++) { + result[i] = C_ARRAY; + } + System.arraycopy(typeSignature, 0, result, arrayCount, sigLength); + return result; +} +/** + * Creates a new type signature with the given amount of array nesting added + * to the given type signature. + * + * @param typeSignature the type signature + * @param arrayCount the desired number of levels of array nesting + * @return the encoded array type signature + */ +public static String createArraySignature(String typeSignature, int arrayCount) { + return new String(createArraySignature(typeSignature.toCharArray(), arrayCount)); +} +/** + * Creates a method signature from the given parameter and return type + * signatures. The encoded method signature is dot-based. + * + * @param parameterTypes the list of parameter type signatures + * @param returnType the return type signature + * @return the encoded method signature + * + * @since 2.0 + */ +public static char[] createMethodSignature(char[][] parameterTypes, char[] returnType) { + int parameterTypesLength = parameterTypes.length; + int parameterLength = 0; + for (int i = 0; i < parameterTypesLength; i++) { + parameterLength += parameterTypes[i].length; + + } + int returnTypeLength = returnType.length; + char[] result = new char[1 + parameterLength + 1 + returnTypeLength]; + result[0] = C_PARAM_START; + int index = 1; + for (int i = 0; i < parameterTypesLength; i++) { + char[] parameterType = parameterTypes[i]; + int length = parameterType.length; + System.arraycopy(parameterType, 0, result, index, length); + index += length; + } + result[index] = C_PARAM_END; + System.arraycopy(returnType, 0, result, index+1, returnTypeLength); + return result; +} +/** + * Creates a method signature from the given parameter and return type + * signatures. The encoded method signature is dot-based. + * + * @param parameterTypes the list of parameter type signatures + * @param returnType the return type signature + * @return the encoded method signature + */ +public static String createMethodSignature(String[] parameterTypes, String returnType) { + int parameterTypesLenth = parameterTypes.length; + char[][] parameters = new char[parameterTypesLenth][]; + for (int i = 0; i < parameterTypesLenth; i++) { + parameters[i] = parameterTypes[i].toCharArray(); + } + return new String(createMethodSignature(parameters, returnType.toCharArray())); +} +/** + * Creates a new type signature from the given type name encoded as a character + * array. This method is equivalent to + * createTypeSignature(new String(typeName),isResolved), although + * more efficient for callers with character arrays rather than strings. If the + * type name is qualified, then it is expected to be dot-based. + * + * @param typeName the possibly qualified type name + * @param isResolved true if the type name is to be considered + * resolved (for example, a type name from a binary class file), and + * false if the type name is to be considered unresolved + * (for example, a type name found in source code) + * @return the encoded type signature + * @see #createTypeSignature(java.lang.String,boolean) + */ +public static String createTypeSignature(char[] typeName, boolean isResolved) { + return new String(createCharArrayTypeSignature(typeName, isResolved)); +} +/** + * Creates a new type signature from the given type name encoded as a character + * array. This method is equivalent to + * createTypeSignature(new String(typeName),isResolved).toCharArray(), although + * more efficient for callers with character arrays rather than strings. If the + * type name is qualified, then it is expected to be dot-based. + * + * @param typeName the possibly qualified type name + * @param isResolved true if the type name is to be considered + * resolved (for example, a type name from a binary class file), and + * false if the type name is to be considered unresolved + * (for example, a type name found in source code) + * @return the encoded type signature + * @see #createTypeSignature(java.lang.String,boolean) + * + * @since 2.0 + */ +public static char[] createCharArrayTypeSignature(char[] typeName, boolean isResolved) { + try { + Scanner scanner = new Scanner(); + scanner.setSource(typeName); + int token = scanner.getNextToken(); + boolean primitive = true; + char primitiveSig = ' '; + StringBuffer sig = null; + int arrayCount = 0; + switch (token) { + case ITerminalSymbols.TokenNameIdentifier : + char[] idSource = scanner.getCurrentIdentifierSource(); + sig = new StringBuffer(idSource.length); + sig.append(idSource); + primitive = false; + break; +// case ITerminalSymbols.TokenNameboolean : +// primitiveSig = Signature.C_BOOLEAN; +// break; +// case ITerminalSymbols.TokenNamebyte : +// primitiveSig = Signature.C_BYTE; +// break; +// case ITerminalSymbols.TokenNamechar : +// primitiveSig = Signature.C_CHAR; +// break; +// case ITerminalSymbols.TokenNamedouble : +// primitiveSig = Signature.C_DOUBLE; +// break; +// case ITerminalSymbols.TokenNamefloat : +// primitiveSig = Signature.C_FLOAT; +// break; +// case ITerminalSymbols.TokenNameint : +// primitiveSig = Signature.C_INT; +// break; +// case ITerminalSymbols.TokenNamelong : +// primitiveSig = Signature.C_LONG; +// break; +// case ITerminalSymbols.TokenNameshort : +// primitiveSig = Signature.C_SHORT; +// break; +// case ITerminalSymbols.TokenNamevoid : +// primitiveSig = Signature.C_VOID; +// break; + default : + throw new IllegalArgumentException(); + } + token = scanner.getNextToken(); + while (!primitive && token == ITerminalSymbols.TokenNameDOT) { + sig.append(scanner.getCurrentIdentifierSource()); + token = scanner.getNextToken(); + if (token == ITerminalSymbols.TokenNameIdentifier) { + sig.append(scanner.getCurrentIdentifierSource()); + token = scanner.getNextToken(); + } else { + throw new IllegalArgumentException(); + } + } + while (token == ITerminalSymbols.TokenNameLBRACKET) { + token = scanner.getNextToken(); + if (token != ITerminalSymbols.TokenNameRBRACKET) + throw new IllegalArgumentException(); + arrayCount++; + token = scanner.getNextToken(); + } + if (token != ITerminalSymbols.TokenNameEOF) + throw new IllegalArgumentException(); + char[] result; + if (primitive) { + result = new char[arrayCount+1]; + result[arrayCount] = primitiveSig; + } else { + int sigLength = sig.length(); + int resultLength = arrayCount + 1 + sigLength + 1; // e.g. '[[[Ljava.lang.String;' + result = new char[resultLength]; + sig.getChars(0, sigLength, result, arrayCount + 1); + result[arrayCount] = isResolved ? C_RESOLVED : C_UNRESOLVED; + result[resultLength-1] = C_NAME_END; + } + for (int i = 0; i < arrayCount; i++) { + result[i] = C_ARRAY; + } + return result; + } catch (InvalidInputException e) { + throw new IllegalArgumentException(); + } +} +/** + * Creates a new type signature from the given type name. If the type name is qualified, + * then it is expected to be dot-based. + *

    + * For example: + *

    + * 
    + * createTypeSignature("int", hucairz) -> "I"
    + * createTypeSignature("java.lang.String", true) -> "Ljava.lang.String;"
    + * createTypeSignature("String", false) -> "QString;"
    + * createTypeSignature("java.lang.String", false) -> "Qjava.lang.String;"
    + * createTypeSignature("int []", false) -> "[I"
    + * 
    + * 
    + *

    + * + * @param typeName the possibly qualified type name + * @param isResolved true if the type name is to be considered + * resolved (for example, a type name from a binary class file), and + * false if the type name is to be considered unresolved + * (for example, a type name found in source code) + * @return the encoded type signature + */ +public static String createTypeSignature(String typeName, boolean isResolved) { + return createTypeSignature(typeName.toCharArray(), isResolved); +} +/** + * Returns the array count (array nesting depth) of the given type signature. + * + * @param typeSignature the type signature + * @return the array nesting depth, or 0 if not an array + * @exception IllegalArgumentException if the signature is not syntactically + * correct + * + * @since 2.0 + */ +public static int getArrayCount(char[] typeSignature) throws IllegalArgumentException { + try { + int count = 0; + while (typeSignature[count] == C_ARRAY) { + ++count; + } + return count; + } catch (ArrayIndexOutOfBoundsException e) { // signature is syntactically incorrect if last character is C_ARRAY + throw new IllegalArgumentException(); + } +} +/** + * Returns the array count (array nesting depth) of the given type signature. + * + * @param typeSignature the type signature + * @return the array nesting depth, or 0 if not an array + * @exception IllegalArgumentException if the signature is not syntactically + * correct + */ +public static int getArrayCount(String typeSignature) throws IllegalArgumentException { + return getArrayCount(typeSignature.toCharArray()); +} +/** + * Returns the type signature without any array nesting. + *

    + * For example: + *

    + * 
    + * getElementType({'[', '[', 'I'}) --> {'I'}.
    + * 
    + * 
    + *

    + * + * @param typeSignature the type signature + * @return the type signature without arrays + * @exception IllegalArgumentException if the signature is not syntactically + * correct + * + * @since 2.0 + */ +public static char[] getElementType(char[] typeSignature) throws IllegalArgumentException { + int count = getArrayCount(typeSignature); + if (count == 0) return typeSignature; + int length = typeSignature.length; + char[] result = new char[length-count]; + System.arraycopy(typeSignature, count, result, 0, length-count); + return result; +} +/** + * Returns the type signature without any array nesting. + *

    + * For example: + *

    + * 
    + * getElementType("[[I") --> "I".
    + * 
    + * 
    + *

    + * + * @param typeSignature the type signature + * @return the type signature without arrays + * @exception IllegalArgumentException if the signature is not syntactically + * correct + */ +public static String getElementType(String typeSignature) throws IllegalArgumentException { + return new String(getElementType(typeSignature.toCharArray())); +} +/** + * Returns the number of parameter types in the given method signature. + * + * @param methodSignature the method signature + * @return the number of parameters + * @exception IllegalArgumentException if the signature is not syntactically + * correct + * @since 2.0 + */ +public static int getParameterCount(char[] methodSignature) throws IllegalArgumentException { + try { + int count = 0; + int i = CharOperation.indexOf(C_PARAM_START, methodSignature) + 1; + if (i == 0) + throw new IllegalArgumentException(); + for (;;) { + char c = methodSignature[i++]; + switch (c) { + case C_ARRAY : + break; + case C_BOOLEAN : + case C_BYTE : + case C_CHAR : + case C_DOUBLE : + case C_FLOAT : + case C_INT : + case C_LONG : + case C_SHORT : + case C_VOID : + ++count; + break; + case C_RESOLVED : + case C_UNRESOLVED : + i = CharOperation.indexOf(C_SEMICOLON, methodSignature, i) + 1; + if (i == 0) + throw new IllegalArgumentException(); + ++count; + break; + case C_PARAM_END : + return count; + default : + throw new IllegalArgumentException(); + } + } + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(); + } +} +/** + * Returns the number of parameter types in the given method signature. + * + * @param methodSignature the method signature + * @return the number of parameters + * @exception IllegalArgumentException if the signature is not syntactically + * correct + */ +public static int getParameterCount(String methodSignature) throws IllegalArgumentException { + return getParameterCount(methodSignature.toCharArray()); +} +/** + * Extracts the parameter type signatures from the given method signature. + * The method signature is expected to be dot-based. + * + * @param methodSignature the method signature + * @return the list of parameter type signatures + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + * + * @since 2.0 + */ +public static char[][] getParameterTypes(char[] methodSignature) throws IllegalArgumentException { + try { + int count = getParameterCount(methodSignature); + char[][] result = new char[count][]; + if (count == 0) + return result; + int i = CharOperation.indexOf(C_PARAM_START, methodSignature) + 1; + count = 0; + int start = i; + for (;;) { + char c = methodSignature[i++]; + switch (c) { + case C_ARRAY : + // array depth is i - start; + break; + case C_BOOLEAN : + case C_BYTE : + case C_CHAR : + case C_DOUBLE : + case C_FLOAT : + case C_INT : + case C_LONG : + case C_SHORT : + case C_VOID : + // common case of base types + if (i - start == 1) { + switch (c) { + case C_BOOLEAN : + result[count++] = new char[] {C_BOOLEAN}; + break; + case C_BYTE : + result[count++] = new char[] {C_BYTE}; + break; + case C_CHAR : + result[count++] = new char[] {C_CHAR}; + break; + case C_DOUBLE : + result[count++] = new char[] {C_DOUBLE}; + break; + case C_FLOAT : + result[count++] = new char[] {C_FLOAT}; + break; + case C_INT : + result[count++] = new char[] {C_INT}; + break; + case C_LONG : + result[count++] = new char[] {C_LONG}; + break; + case C_SHORT : + result[count++] = new char[] {C_SHORT}; + break; + case C_VOID : + result[count++] = new char[] {C_VOID}; + break; + } + } else { + result[count++] = CharOperation.subarray(methodSignature, start, i); + } + start = i; + break; + case C_RESOLVED : + case C_UNRESOLVED : + i = CharOperation.indexOf(C_SEMICOLON, methodSignature, i) + 1; + if (i == 0) + throw new IllegalArgumentException(); + result[count++] = CharOperation.subarray(methodSignature, start, i); + start = i; + break; + case C_PARAM_END: + return result; + default : + throw new IllegalArgumentException(); + } + } + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(); + } +} +/** + * Extracts the parameter type signatures from the given method signature. + * The method signature is expected to be dot-based. + * + * @param methodSignature the method signature + * @return the list of parameter type signatures + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + */ +public static String[] getParameterTypes(String methodSignature) throws IllegalArgumentException { + char[][] parameterTypes = getParameterTypes(methodSignature.toCharArray()); + int length = parameterTypes.length; + String[] result = new String[length]; + for (int i = 0; i < length; i++) { + result[i] = new String(parameterTypes[i]); + } + return result; +} +/** + * Returns a char array containing all but the last segment of the given + * dot-separated qualified name. Returns the empty char array if it is not qualified. + *

    + * For example: + *

    + * 
    + * getQualifier({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g'}
    + * getQualifier({'O', 'u', 't', 'e', 'r', '.', 'I', 'n', 'n', 'e', 'r'}) -> {'O', 'u', 't', 'e', 'r'}
    + * 
    + * 
    + *

    + * + * @param name the name + * @return the qualifier prefix, or the empty char array if the name contains no + * dots + * + * @since 2.0 + */ +public static char[] getQualifier(char[] name) { + int lastDot = CharOperation.lastIndexOf(C_DOT, name); + if (lastDot == -1) { + return NO_CHAR; //$NON-NLS-1$ + } + return CharOperation.subarray(name, 0, lastDot); +} +/** + * Returns a string containing all but the last segment of the given + * dot-separated qualified name. Returns the empty string if it is not qualified. + *

    + * For example: + *

    + * 
    + * getQualifier("java.lang.Object") -> "java.lang"
    + * getQualifier("Outer.Inner") -> "Outer"
    + * 
    + * 
    + *

    + * + * @param name the name + * @return the qualifier prefix, or the empty string if the name contains no + * dots + */ +public static String getQualifier(String name) { + return new String(getQualifier(name.toCharArray())); +} +/** + * Extracts the return type from the given method signature. The method signature is + * expected to be dot-based. + * + * @param methodSignature the method signature + * @return the type signature of the return type + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + * + * @since 2.0 + */ +public static char[] getReturnType(char[] methodSignature) throws IllegalArgumentException { + int i = CharOperation.lastIndexOf(C_PARAM_END, methodSignature); + if (i == -1) { + throw new IllegalArgumentException(); + } + return CharOperation.subarray(methodSignature, i + 1, methodSignature.length); +} +/** + * Extracts the return type from the given method signature. The method signature is + * expected to be dot-based. + * + * @param methodSignature the method signature + * @return the type signature of the return type + * @exception IllegalArgumentException if the signature is syntactically + * incorrect + */ +public static String getReturnType(String methodSignature) throws IllegalArgumentException { + return new String(getReturnType(methodSignature.toCharArray())); +} +/** + * Returns the last segment of the given dot-separated qualified name. + * Returns the given name if it is not qualified. + *

    + * For example: + *

    + * 
    + * getSimpleName({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {'O', 'b', 'j', 'e', 'c', 't'}
    + * 
    + * 
    + *

    + * + * @param name the name + * @return the last segment of the qualified name + * + * @since 2.0 + */ +public static char[] getSimpleName(char[] name) { + int lastDot = CharOperation.lastIndexOf(C_DOT, name); + if (lastDot == -1) { + return name; + } + return CharOperation.subarray(name, lastDot + 1, name.length); +} +/** + * Returns the last segment of the given dot-separated qualified name. + * Returns the given name if it is not qualified. + *

    + * For example: + *

    + * 
    + * getSimpleName("java.lang.Object") -> "Object"
    + * 
    + * 
    + *

    + * + * @param name the name + * @return the last segment of the qualified name + */ +public static String getSimpleName(String name) { + return new String(getSimpleName(name.toCharArray())); +} +/** + * Returns all segments of the given dot-separated qualified name. + * Returns an array with only the given name if it is not qualified. + * Returns an empty array if the name is empty. + *

    + * For example: + *

    + * 
    + * getSimpleNames({'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}) -> {{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}
    + * getSimpleNames({'O', 'b', 'j', 'e', 'c', 't'}) -> {{'O', 'b', 'j', 'e', 'c', 't'}}
    + * getSimpleNames("") -> {}
    + * 
    + * 
    + * + * @param name the name + * @return the list of simple names, possibly empty + * + * @since 2.0 + */ +public static char[][] getSimpleNames(char[] name) { + if (name.length == 0) { + return NO_CHAR_CHAR; + } + int dot = CharOperation.indexOf(C_DOT, name); + if (dot == -1) { + return new char[][] {name}; + } + int n = 1; + while ((dot = CharOperation.indexOf(C_DOT, name, dot + 1)) != -1) { + ++n; + } + char[][] result = new char[n + 1][]; + int segStart = 0; + for (int i = 0; i < n; ++i) { + dot = CharOperation.indexOf(C_DOT, name, segStart); + result[i] = CharOperation.subarray(name, segStart, dot); + segStart = dot + 1; + } + result[n] = CharOperation.subarray(name, segStart, name.length); + return result; +} +/** + * Returns all segments of the given dot-separated qualified name. + * Returns an array with only the given name if it is not qualified. + * Returns an empty array if the name is empty. + *

    + * For example: + *

    + * 
    + * getSimpleNames("java.lang.Object") -> {"java", "lang", "Object"}
    + * getSimpleNames("Object") -> {"Object"}
    + * getSimpleNames("") -> {}
    + * 
    + * 
    + * + * @param name the name + * @return the list of simple names, possibly empty + */ +public static String[] getSimpleNames(String name) { + char[][] simpleNames = getSimpleNames(name.toCharArray()); + int length = simpleNames.length; + String[] result = new String[length]; + for (int i = 0; i < length; i++) { + result[i] = new String(simpleNames[i]); + } + return result; +} +/** + * Converts the given method signature to a readable form. The method signature is expected to + * be dot-based. + *

    + * For example: + *

    + * 
    + * toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
    + * 
    + * 
    + *

    + * + * @param methodSignature the method signature to convert + * @param methodName the name of the method to insert in the result, or + * null if no method name is to be included + * @param parameterNames the parameter names to insert in the result, or + * null if no parameter names are to be included; if supplied, + * the number of parameter names must match that of the method signature + * @param fullyQualifyTypeNames true if type names should be fully + * qualified, and false to use only simple names + * @param includeReturnType true if the return type is to be + * included + * @return the char array representation of the method signature + * + * @since 2.0 + */ +public static char[] toCharArray(char[] methodSignature, char[] methodName, char[][] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) { + try { + int firstParen = CharOperation.indexOf(C_PARAM_START, methodSignature); + if (firstParen == -1) throw new IllegalArgumentException(); + + int sigLength = methodSignature.length; + + // compute result length + + // method signature + int paramCount = 0; + int lastParen = -1; + int resultLength = 0; + signature: for (int i = firstParen; i < sigLength; i++) { + switch (methodSignature[i]) { + case C_ARRAY : + resultLength += 2; // [] + continue signature; + case C_BOOLEAN : + resultLength += BOOLEAN.length; + break; + case C_BYTE : + resultLength += BYTE.length; + break; + case C_CHAR : + resultLength += CHAR.length; + break; + case C_DOUBLE : + resultLength += DOUBLE.length; + break; + case C_FLOAT : + resultLength += FLOAT.length; + break; + case C_INT : + resultLength += INT.length; + break; + case C_LONG : + resultLength += LONG.length; + break; + case C_SHORT : + resultLength += SHORT.length; + break; + case C_VOID : + resultLength += VOID.length; + break; + case C_RESOLVED : + case C_UNRESOLVED : + int end = CharOperation.indexOf(C_SEMICOLON, methodSignature, i); + if (end == -1) throw new IllegalArgumentException(); + int start; + if (fullyQualifyTypeNames) { + start = i+1; + } else { + start = CharOperation.lastIndexOf(C_DOT, methodSignature, i, end) + 1; + if (start == 0) start = i+1; + } + resultLength += end-start; + i = end; + break; + case C_PARAM_START : + // add space for "(" + resultLength++; + continue signature; + case C_PARAM_END : + lastParen = i; + if (includeReturnType) { + if (paramCount > 0) { + // remove space for ", " that was added with last parameter and remove space that is going to be added for ", " after return type + // and add space for ") " + resultLength -= 2; + } //else + // remove space that is going to be added for ", " after return type + // and add space for ") " + // -> noop + + // decrement param count because it is going to be added for return type + paramCount--; + continue signature; + } else { + if (paramCount > 0) { + // remove space for ", " that was added with last parameter and add space for ")" + resultLength--; + } else { + // add space for ")" + resultLength++; + } + break signature; + } + default : + throw new IllegalArgumentException(); + } + resultLength += 2; // add space for ", " + paramCount++; + } + + // parameter names + int parameterNamesLength = parameterNames == null ? 0 : parameterNames.length; + for (int i = 0; i >> 32); + result[index++] = ' '; + } + + // selector + if (methodName != null) { + System.arraycopy(methodName, 0, result, index, selectorLength); + index += selectorLength; + } + + // parameters + result[index++] = C_PARAM_START; + int sigPos = firstParen+1; + for (int i = 0; i < paramCount; i++) { + long pos = copyType(methodSignature, sigPos, result, index, fullyQualifyTypeNames); + index = (int) (pos >>> 32); + sigPos = (int)pos; + if (parameterNames != null) { + result[index++] = ' '; + char[] parameterName = parameterNames[i]; + int paramLength = parameterName.length; + System.arraycopy(parameterName, 0, result, index, paramLength); + index += paramLength; + } + if (i != paramCount-1) { + result[index++] = ','; + result[index++] = ' '; + } + } + if (sigPos >= sigLength) { + throw new IllegalArgumentException(); // should be on last paren + } + result[index++] = C_PARAM_END; + + return result; + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(); + } +} +/** + * Converts the given type signature to a readable string. The signature is expected to + * be dot-based. + * + *

    + * For example: + *

    + * 
    + * toString({'[', 'L', 'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', ';'}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'S', 't', 'r', 'i', 'n', 'g', '[', ']'}
    + * toString({'I'}) -> {'i', 'n', 't'}
    + * 
    + * 
    + *

    + *

    + * Note: This method assumes that a type signature containing a '$' + * is an inner type signature. While this is correct in most cases, someone could + * define a non-inner type name containing a '$'. Handling this + * correctly in all cases would have required resolving the signature, which + * generally not feasible. + *

    + * + * @param signature the type signature + * @return the string representation of the type + * @exception IllegalArgumentException if the signature is not syntactically + * correct + * + * @since 2.0 + */ +public static char[] toCharArray(char[] signature) throws IllegalArgumentException { + try { + int sigLength = signature.length; + + if (sigLength == 0 || signature[0] == C_PARAM_START) { + return toCharArray(signature, NO_CHAR, null, true, true); + } + + // compute result length + int resultLength = 0; + int index = -1; + while (signature[++index] == C_ARRAY) { + resultLength += 2; // [] + } + switch (signature[index]) { + case C_BOOLEAN : + resultLength += BOOLEAN.length; + break; + case C_BYTE : + resultLength += BYTE.length; + break; + case C_CHAR : + resultLength += CHAR.length; + break; + case C_DOUBLE : + resultLength += DOUBLE.length; + break; + case C_FLOAT : + resultLength += FLOAT.length; + break; + case C_INT : + resultLength += INT.length; + break; + case C_LONG : + resultLength += LONG.length; + break; + case C_SHORT : + resultLength += SHORT.length; + break; + case C_VOID : + resultLength += VOID.length; + break; + case C_RESOLVED : + case C_UNRESOLVED : + int end = CharOperation.indexOf(C_SEMICOLON, signature, index); + if (end == -1) throw new IllegalArgumentException(); + int start = index + 1; + resultLength += end-start; + break; + default : + throw new IllegalArgumentException(); + } + + char[] result = new char[resultLength]; + copyType(signature, 0, result, 0, true); + + /** + * Converts '$' separated type signatures into '.' separated type signature. + * NOTE: This assumes that the type signature is an inner type signature. + * This is true in most cases, but someone can define a non-inner type + * name containing a '$'. However to tell the difference, we would have + * to resolve the signature, which cannot be done at this point. + */ + CharOperation.replace(result, C_DOLLAR, C_DOT); + + return result; + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalArgumentException(); + } +} +/** + * Converts the given array of qualified name segments to a qualified name. + *

    + * For example: + *

    + * 
    + * toQualifiedName({{'j', 'a', 'v', 'a'}, {'l', 'a', 'n', 'g'}, {'O', 'b', 'j', 'e', 'c', 't'}}) -> {'j', 'a', 'v', 'a', '.', 'l', 'a', 'n', 'g', '.', 'O', 'b', 'j', 'e', 'c', 't'}
    + * toQualifiedName({{'O', 'b', 'j', 'e', 'c', 't'}}) -> {'O', 'b', 'j', 'e', 'c', 't'}
    + * toQualifiedName({{}}) -> {}
    + * 
    + * 
    + *

    + * + * @param segments the list of name segments, possibly empty + * @return the dot-separated qualified name, or the empty string + * + * @since 2.0 + */ +public static char[] toQualifiedName(char[][] segments) { + int length = segments.length; + if (length == 0) return NO_CHAR; + if (length == 1) return segments[0]; + + int resultLength = 0; + for (int i = 0; i < length; i++) { + resultLength += segments[i].length+1; + } + resultLength--; + char[] result = new char[resultLength]; + int index = 0; + for (int i = 0; i < length; i++) { + char[] segment = segments[i]; + int segmentLength = segment.length; + System.arraycopy(segment, 0, result, index, segmentLength); + index += segmentLength; + if (i != length-1) { + result[index++] = C_DOT; + } + } + return result; +} +/** + * Converts the given array of qualified name segments to a qualified name. + *

    + * For example: + *

    + * 
    + * toQualifiedName(new String[] {"java", "lang", "Object"}) -> "java.lang.Object"
    + * toQualifiedName(new String[] {"Object"}) -> "Object"
    + * toQualifiedName(new String[0]) -> ""
    + * 
    + * 
    + *

    + * + * @param segments the list of name segments, possibly empty + * @return the dot-separated qualified name, or the empty string + */ +public static String toQualifiedName(String[] segments) { + int length = segments.length; + char[][] charArrays = new char[length][]; + for (int i = 0; i < length; i++) { + charArrays[i] = segments[i].toCharArray(); + } + return new String(toQualifiedName(charArrays)); +} +/** + * Converts the given type signature to a readable string. The signature is expected to + * be dot-based. + * + *

    + * For example: + *

    + * 
    + * toString("[Ljava.lang.String;") -> "java.lang.String[]"
    + * toString("I") -> "int"
    + * 
    + * 
    + *

    + *

    + * Note: This method assumes that a type signature containing a '$' + * is an inner type signature. While this is correct in most cases, someone could + * define a non-inner type name containing a '$'. Handling this + * correctly in all cases would have required resolving the signature, which + * generally not feasible. + *

    + * + * @param signature the type signature + * @return the string representation of the type + * @exception IllegalArgumentException if the signature is not syntactically + * correct + */ +public static String toString(String signature) throws IllegalArgumentException { + return new String(toCharArray(signature.toCharArray())); +} +/** + * Converts the given method signature to a readable string. The method signature is expected to + * be dot-based. + *

    + * For example: + *

    + * 
    + * toString("([Ljava.lang.String;)V", "main", new String[] {"args"}, false, true) -> "void main(String[] args)"
    + * 
    + * 
    + *

    + * + * @param methodSignature the method signature to convert + * @param methodName the name of the method to insert in the result, or + * null if no method name is to be included + * @param parameterNames the parameter names to insert in the result, or + * null if no parameter names are to be included; if supplied, + * the number of parameter names must match that of the method signature + * @param fullyQualifyTypeNames true if type names should be fully + * qualified, and false to use only simple names + * @param includeReturnType true if the return type is to be + * included + * @return the string representation of the method signature + */ +public static String toString(String methodSignature, String methodName, String[] parameterNames, boolean fullyQualifyTypeNames, boolean includeReturnType) { + char[][] params; + if (parameterNames == null) { + params = null; + } else { + int paramLength = parameterNames.length; + params = new char[paramLength][]; + for (int i = 0; i < paramLength; i++) { + params[i] = parameterNames[i].toCharArray(); + } + } + return new String(toCharArray(methodSignature.toCharArray(), methodName == null ? null : methodName.toCharArray(), params, fullyQualifyTypeNames, includeReturnType)); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/CompletionEngine.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/CompletionEngine.java new file mode 100644 index 0000000..8d4ed79 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/CompletionEngine.java @@ -0,0 +1,2702 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist; + +import java.util.*; + +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.env.*; + +import net.sourceforge.phpdt.internal.codeassist.impl.*; +import net.sourceforge.phpdt.core.ICompletionRequestor; +import net.sourceforge.phpdt.core.IType; +//import net.sourceforge.phpdt.core.JavaCore; +//import net.sourceforge.phpdt.core.JavaModelException; +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.internal.codeassist.complete.*; + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; +import net.sourceforge.phpdt.internal.core.BasicCompilationUnit; +import net.sourceforge.phpdt.internal.core.TypeConverter; +import net.sourceforge.phpdt.internal.compiler.impl.*; + +/** + * This class is the entry point for source completions. + * It contains two public APIs used to call CodeAssist on a given source with + * a given environment, assisting position and storage (and possibly options). + */ +public final class CompletionEngine + extends Engine + implements ISearchRequestor, TypeConstants , ITerminalSymbols , RelevanceConstants { + + public static boolean DEBUG = false; + + private final static char[] ERROR_PATTERN = "*error*".toCharArray(); //$NON-NLS-1$ + private final static char[] EXCEPTION_PATTERN = "*exception*".toCharArray(); //$NON-NLS-1$ + private final static char[] SEMICOLON = new char[] { ';' }; + TypeBinding[] expectedTypes; + + boolean assistNodeIsClass; + boolean assistNodeIsException; + boolean assistNodeIsInterface; + + CompletionParser parser; + ICompletionRequestor requestor; + ProblemReporter problemReporter; + char[] source; + char[] token; + boolean resolvingImports = false; + boolean insideQualifiedReference = false; + int startPosition, actualCompletionPosition, endPosition, offset; + HashtableOfObject knownPkgs = new HashtableOfObject(10); + HashtableOfObject knownTypes = new HashtableOfObject(10); + Scanner nameScanner; + + /* + static final char[][] mainDeclarations = + new char[][] { + "package".toCharArray(), + "import".toCharArray(), + "abstract".toCharArray(), + "final".toCharArray(), + "public".toCharArray(), + "class".toCharArray(), + "interface".toCharArray()}; + + static final char[][] modifiers = // may want field, method, type & member type modifiers + new char[][] { + "abstract".toCharArray(), + "final".toCharArray(), + "native".toCharArray(), + "public".toCharArray(), + "protected".toCharArray(), + "private".toCharArray(), + "static".toCharArray(), + "strictfp".toCharArray(), + "synchronized".toCharArray(), + "transient".toCharArray(), + "volatile".toCharArray()}; + */ + static final char[][] baseTypes = new char[][] { + "boolean".toCharArray(), //$NON-NLS-1$ + "byte".toCharArray(), //$NON-NLS-1$ + "char".toCharArray(), //$NON-NLS-1$ + "double".toCharArray(), //$NON-NLS-1$ + "float".toCharArray(), //$NON-NLS-1$ + "int".toCharArray(), //$NON-NLS-1$ + "long".toCharArray(), //$NON-NLS-1$ + "short".toCharArray(), //$NON-NLS-1$ + "void".toCharArray(), //$NON-NLS-1$ + }; + + static final char[] classField = "class".toCharArray(); //$NON-NLS-1$ + static final char[] lengthField = "length".toCharArray(); //$NON-NLS-1$ + static final char[] THIS = "this".toCharArray(); //$NON-NLS-1$ + static final char[] THROWS = "throws".toCharArray(); //$NON-NLS-1$ + + static InvocationSite FakeInvocationSite = new InvocationSite(){ + public boolean isSuperAccess(){ return false; } + public boolean isTypeAccess(){ return false; } + public void setActualReceiverType(ReferenceBinding receiverType) {} + public void setDepth(int depth){} + public void setFieldIndex(int depth){} + }; + + /** + * The CompletionEngine is responsible for computing source completions. + * + * It requires a searchable name environment, which supports some + * specific search APIs, and a requestor to feed back the results to a UI. + * + * @param nameEnvironment net.sourceforge.phpdt.internal.codeassist.ISearchableNameEnvironment + * used to resolve type/package references and search for types/packages + * based on partial names. + * + * @param requestor net.sourceforge.phpdt.internal.codeassist.ICompletionRequestor + * since the engine might produce answers of various forms, the engine + * is associated with a requestor able to accept all possible completions. + * + * @param settings java.util.Map + * set of options used to configure the code assist engine. + */ + public CompletionEngine( + ISearchableNameEnvironment nameEnvironment, + ICompletionRequestor requestor, + Map settings) { + + super(settings); + this.requestor = requestor; + this.nameEnvironment = nameEnvironment; + + problemReporter = new ProblemReporter( + DefaultErrorHandlingPolicies.proceedWithAllProblems(), + this.compilerOptions, + new DefaultProblemFactory(Locale.getDefault()) { + public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) { + if (problem.isError() && (problem.getID() & IProblem.Syntax) != 0) { + CompletionEngine.this.requestor.acceptError(problem); + } + } + }); + this.parser = + new CompletionParser(problemReporter, this.compilerOptions.assertMode); + this.lookupEnvironment = + new LookupEnvironment(this, this.compilerOptions, problemReporter, nameEnvironment); + this.nameScanner = + new Scanner(false, false, false, this.compilerOptions.assertMode); + } + + /** + * One result of the search consists of a new class. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ + public void acceptClass(char[] packageName, char[] className, int modifiers) { + + char[] fullyQualifiedName = CharOperation.concat(packageName, className, '.'); + char[] completionName = fullyQualifiedName; + + if (this.knownTypes.containsKey(completionName)) return; + + this.knownTypes.put(completionName, this); + + int relevance = R_DEFAULT; + if (resolvingImports) { + completionName = CharOperation.concat(completionName, SEMICOLON); + relevance += computeRelevanceForCaseMatching(token, fullyQualifiedName); + } else { + if (!insideQualifiedReference) { + if (mustQualifyType(packageName, className)) { + if (packageName == null || packageName.length == 0) + if (unitScope != null && unitScope.fPackage.compoundName != NoCharChar) + return; // ignore types from the default package from outside it + } else { + completionName = className; + } + } + relevance += computeRelevanceForCaseMatching(token, className); + relevance += computeRelevanceForExpectingType(packageName, className); + relevance += computeRelevanceForClass(); + relevance += computeRelevanceForException(className); + } + + requestor.acceptClass( + packageName, + className, + completionName, + modifiers, + startPosition - offset, + endPosition - offset, + relevance); + } + + /** + * One result of the search consists of a new interface. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.I". + * The default package is represented by an empty array. + */ + public void acceptInterface( + char[] packageName, + char[] interfaceName, + int modifiers) { + + char[] fullyQualifiedName = CharOperation.concat(packageName, interfaceName, '.'); + char[] completionName = fullyQualifiedName; + + if (this.knownTypes.containsKey(completionName)) return; + + this.knownTypes.put(completionName, this); + + int relevance = R_DEFAULT; + if (resolvingImports) { + completionName = CharOperation.concat(completionName, new char[] { ';' }); + relevance += computeRelevanceForCaseMatching(token, fullyQualifiedName); + } else { + if (!insideQualifiedReference) { + if (mustQualifyType(packageName, interfaceName)) { + if (packageName == null || packageName.length == 0) + if (unitScope != null && unitScope.fPackage.compoundName != NoCharChar) + return; // ignore types from the default package from outside it + } else { + completionName = interfaceName; + } + } + relevance += computeRelevanceForCaseMatching(token, interfaceName); + relevance += computeRelevanceForExpectingType(packageName, interfaceName); + relevance += computeRelevanceForInterface(); + } + + requestor.acceptInterface( + packageName, + interfaceName, + completionName, + modifiers, + startPosition - offset, + endPosition - offset, + relevance); + } + + /** + * One result of the search consists of a new package. + * + * NOTE - All package names are presented in their readable form: + * Package names are in the form "a.b.c". + * The default package is represented by an empty array. + */ + public void acceptPackage(char[] packageName) { + + if (this.knownPkgs.containsKey(packageName)) return; + + this.knownPkgs.put(packageName, this); + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(token, packageName); + + requestor.acceptPackage( + packageName, + resolvingImports + ? CharOperation.concat(packageName, new char[] { '.', '*', ';' }) + : packageName, + startPosition - offset, + endPosition - offset, + relevance); + } + + /** + * One result of the search consists of a new type. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ + public void acceptType(char[] packageName, char[] typeName) { + + char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.'); + char[] completionName = fullyQualifiedName; + + if (this.knownTypes.containsKey(completionName)) return; + + this.knownTypes.put(completionName, this); + + int relevance = R_DEFAULT; + if (resolvingImports) { + completionName = CharOperation.concat(completionName, new char[] { ';' }); + relevance += computeRelevanceForCaseMatching(token, fullyQualifiedName); + } else { + if (!insideQualifiedReference) { + if (mustQualifyType(packageName, typeName)) { + if (packageName == null || packageName.length == 0) + if (unitScope != null && unitScope.fPackage.compoundName != NoCharChar) + return; // ignore types from the default package from outside it + } else { + completionName = typeName; + } + } + relevance += computeRelevanceForCaseMatching(token, typeName); + relevance += computeRelevanceForExpectingType(packageName, typeName); + } + + requestor.acceptType( + packageName, + typeName, + completionName, + startPosition - offset, + endPosition - offset, + relevance); + } + + private void complete(AstNode astNode, Binding qualifiedBinding, Scope scope) { + + setSourceRange(astNode.sourceStart, astNode.sourceEnd); + + if(parser.assistNodeParent != null) { + computeExpectedTypes(parser.assistNodeParent, scope); + } + + // defaults... some nodes will change these + if (astNode instanceof CompletionOnFieldType) { + + CompletionOnFieldType field = (CompletionOnFieldType) astNode; + CompletionOnSingleTypeReference type = (CompletionOnSingleTypeReference) field.type; + token = type.token; + setSourceRange(type.sourceStart, type.sourceEnd); + // findKeywords(token, modifiers, scope); // could be the start of a field, method or member type + findTypesAndPackages(token, scope); + + if(!field.isLocalVariable && field.modifiers == CompilerModifiers.AccDefault) { + findMethods(token,null,scope.enclosingSourceType(),scope,new ObjectVector(),false,false,true,null,null,false); + } + } else { + if(astNode instanceof CompletionOnMethodReturnType) { + + CompletionOnMethodReturnType method = (CompletionOnMethodReturnType) astNode; + SingleTypeReference type = (CompletionOnSingleTypeReference) method.returnType; + token = type.token; + setSourceRange(type.sourceStart, type.sourceEnd); + findTypesAndPackages(token, scope); + + if(method.modifiers == CompilerModifiers.AccDefault) { + findMethods(token,null,scope.enclosingSourceType(),scope,new ObjectVector(),false,false,true,null,null,false); + } + } else { + + if (astNode instanceof CompletionOnSingleNameReference) { + + token = ((CompletionOnSingleNameReference) astNode).token; + findVariablesAndMethods( + token, + scope, + (CompletionOnSingleNameReference) astNode, + scope); + // can be the start of a qualified type name + findTypesAndPackages(token, scope); + + } else { + + if (astNode instanceof CompletionOnSingleTypeReference) { + + token = ((CompletionOnSingleTypeReference) astNode).token; + + assistNodeIsClass = astNode instanceof CompletionOnClassReference; + assistNodeIsException = astNode instanceof CompletionOnExceptionReference; + assistNodeIsInterface = astNode instanceof CompletionOnInterfaceReference; + + // can be the start of a qualified type name + if (qualifiedBinding == null) { + findTypesAndPackages(token, scope); + } else { + findMemberTypes( + token, + (ReferenceBinding) qualifiedBinding, + scope, + scope.enclosingSourceType()); + } + } else { + + if (astNode instanceof CompletionOnQualifiedNameReference) { + + insideQualifiedReference = true; + CompletionOnQualifiedNameReference ref = + (CompletionOnQualifiedNameReference) astNode; + token = ref.completionIdentifier; + long completionPosition = ref.sourcePositions[ref.sourcePositions.length - 1]; + + if (qualifiedBinding instanceof VariableBinding) { + + setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); + TypeBinding receiverType = ((VariableBinding) qualifiedBinding).type; + if (receiverType != null) { + findFieldsAndMethods(token, receiverType, scope, ref, scope,false); + } + + } else { + + if (qualifiedBinding instanceof ReferenceBinding) { + + ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding; + setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); + + findMemberTypes(token, receiverType, scope, scope.enclosingSourceType()); + + findClassField(token, (TypeBinding) qualifiedBinding, scope); + + findFields( + token, + receiverType, + scope, + new ObjectVector(), + new ObjectVector(), + true, + ref, + scope, + false); + + findMethods( + token, + null, + receiverType, + scope, + new ObjectVector(), + true, + false, + false, + ref, + scope, + false); + + } else { + + if (qualifiedBinding instanceof PackageBinding) { + + setSourceRange(astNode.sourceStart, (int) completionPosition); + // replace to the end of the completion identifier + findTypesAndSubpackages(token, (PackageBinding) qualifiedBinding); + } + } + } + + } else { + + if (astNode instanceof CompletionOnQualifiedTypeReference) { + + insideQualifiedReference = true; + + assistNodeIsClass = astNode instanceof CompletionOnQualifiedClassReference; + assistNodeIsException = astNode instanceof CompletionOnQualifiedExceptionReference; + assistNodeIsInterface = astNode instanceof CompletionOnQualifiedInterfaceReference; + + CompletionOnQualifiedTypeReference ref = + (CompletionOnQualifiedTypeReference) astNode; + token = ref.completionIdentifier; + long completionPosition = ref.sourcePositions[ref.tokens.length]; + + // get the source positions of the completion identifier + if (qualifiedBinding instanceof ReferenceBinding) { + + setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); + findMemberTypes( + token, + (ReferenceBinding) qualifiedBinding, + scope, + scope.enclosingSourceType()); + + } else { + + if (qualifiedBinding instanceof PackageBinding) { + + setSourceRange(astNode.sourceStart, (int) completionPosition); + // replace to the end of the completion identifier + findTypesAndSubpackages(token, (PackageBinding) qualifiedBinding); + } + } + + } else { + + if (astNode instanceof CompletionOnMemberAccess) { + + CompletionOnMemberAccess access = (CompletionOnMemberAccess) astNode; + long completionPosition = access.nameSourcePosition; + setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); + + token = access.token; + + findFieldsAndMethods( + token, + (TypeBinding) qualifiedBinding, + scope, + access, + scope, + false); + + } else { + + if (astNode instanceof CompletionOnMessageSend) { + + CompletionOnMessageSend messageSend = (CompletionOnMessageSend) astNode; + TypeBinding[] argTypes = + computeTypes(messageSend.arguments, (BlockScope) scope); + token = messageSend.selector; + if (qualifiedBinding == null) { + + findImplicitMessageSends(token, argTypes, scope, messageSend, scope); + } else { + + findMethods( + token, + argTypes, + (ReferenceBinding) qualifiedBinding, + scope, + new ObjectVector(), + false, + true, + false, + messageSend, + scope, + false); + } + + } else { + + if (astNode instanceof CompletionOnExplicitConstructorCall) { + + CompletionOnExplicitConstructorCall constructorCall = + (CompletionOnExplicitConstructorCall) astNode; + TypeBinding[] argTypes = + computeTypes(constructorCall.arguments, (BlockScope) scope); + findConstructors( + (ReferenceBinding) qualifiedBinding, + argTypes, + scope, + constructorCall, + false); + + } else { + + if (astNode instanceof CompletionOnQualifiedAllocationExpression) { + + CompletionOnQualifiedAllocationExpression allocExpression = + (CompletionOnQualifiedAllocationExpression) astNode; + TypeBinding[] argTypes = + computeTypes(allocExpression.arguments, (BlockScope) scope); + + ReferenceBinding ref = (ReferenceBinding) qualifiedBinding; + if(ref.isClass()) { + if(!ref.isAbstract()) { + findConstructors( + ref, + argTypes, + scope, + allocExpression, + false); + } + } + if(!ref.isFinal()){ + findAnonymousType( + ref, + argTypes, + scope, + allocExpression); + } + + } else { + + if (astNode instanceof CompletionOnClassLiteralAccess) { + CompletionOnClassLiteralAccess access = (CompletionOnClassLiteralAccess) astNode; + setSourceRange(access.classStart, access.sourceEnd); + + token = access.completionIdentifier; + + findClassField(token, (TypeBinding) qualifiedBinding, scope); + } else { + if(astNode instanceof CompletionOnMethodName) { + CompletionOnMethodName method = (CompletionOnMethodName) astNode; + + setSourceRange(method.sourceStart, method.selectorEnd); + + FieldBinding[] fields = scope.enclosingSourceType().fields(); + char[][] excludeNames = new char[fields.length][]; + for(int i = 0 ; i < fields.length ; i++){ + excludeNames[i] = fields[i].name; + } + + token = method.selector; + + findVariableNames(token, method.returnType, excludeNames); + } else { + if (astNode instanceof CompletionOnFieldName) { + CompletionOnFieldName field = (CompletionOnFieldName) astNode; + + FieldBinding[] fields = scope.enclosingSourceType().fields(); + char[][] excludeNames = new char[fields.length][]; + for(int i = 0 ; i < fields.length ; i++){ + excludeNames[i] = fields[i].name; + } + + token = field.realName; + + findVariableNames(field.realName, field.type, excludeNames); + } else { + if (astNode instanceof CompletionOnLocalName || + astNode instanceof CompletionOnArgumentName){ + LocalDeclaration variable = (LocalDeclaration) astNode; + + LocalVariableBinding[] locals = ((BlockScope)scope).locals; + char[][] excludeNames = new char[locals.length][]; + int localCount = 0; + for(int i = 0 ; i < locals.length ; i++){ + if(locals[i] != null) { + excludeNames[localCount++] = locals[i].name; + } + } + System.arraycopy(excludeNames, 0, excludeNames = new char[localCount][], 0, localCount); + + if(variable instanceof CompletionOnLocalName){ + token = ((CompletionOnLocalName) variable).realName; + } else { + token = ((CompletionOnArgumentName) variable).realName; + } + findVariableNames(token, variable.type, excludeNames); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + +// public void complete(IType type, char[] snippet, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic){ +// TypeConverter converter = new TypeConverter(); +// +// IType topLevelType = type; +// while(topLevelType.getDeclaringType() != null) { +// topLevelType = topLevelType.getDeclaringType(); +// } +// +// CompilationResult compilationResult = new CompilationResult((topLevelType.getElementName() + ".java").toCharArray(), 1, 1, this.compilerOptions.maxProblemsPerUnit); //$NON-NLS-1$ +// +// CompilationUnitDeclaration compilationUnit = new CompilationUnitDeclaration(problemReporter, compilationResult, 0); +// +// try { +// TypeDeclaration typeDeclaration = converter.buildTypeDeclaration(type, compilationUnit, compilationResult, problemReporter); +// +// if(typeDeclaration != null) { +// // build AST from snippet +// Initializer fakeInitializer = parseSnippeInitializer(snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic); +// +// // merge AST +// FieldDeclaration[] oldFields = typeDeclaration.fields; +// FieldDeclaration[] newFields = new FieldDeclaration[oldFields.length + 1]; +// System.arraycopy(oldFields, 0, newFields, 0, oldFields.length); +// newFields[oldFields.length] = fakeInitializer; +// typeDeclaration.fields = newFields; +// +// if(DEBUG) { +// System.out.println("SNIPPET COMPLETION AST :"); //$NON-NLS-1$ +// System.out.println(compilationUnit.toString()); +// } +// +// if (compilationUnit.types != null) { +// try { +// lookupEnvironment.buildTypeBindings(compilationUnit); +// +// if ((unitScope = compilationUnit.scope) != null) { +// lookupEnvironment.completeTypeBindings(compilationUnit, true); +// compilationUnit.scope.faultInTypes(); +// compilationUnit.resolve(); +// } +// } catch (CompletionNodeFound e) { +// // completionNodeFound = true; +// if (e.astNode != null) { +// // if null then we found a problem in the completion node +// complete(e.astNode, e.qualifiedBinding, e.scope); +// } +// } +// } +// } +// } catch(JavaModelException e) { +// // Do nothing +// } +// } + +// private Initializer parseSnippeInitializer(char[] snippet, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic){ +// StringBuffer prefix = new StringBuffer(); +// prefix.append("public class FakeType {\n "); //$NON-NLS-1$ +// if(isStatic) { +// prefix.append("static "); //$NON-NLS-1$ +// } +// prefix.append("{\n"); //$NON-NLS-1$ +// for (int i = 0; i < localVariableTypeNames.length; i++) { +// prefix.append(AstNode.modifiersString(localVariableModifiers[i])); +// prefix.append(' '); +// prefix.append(localVariableTypeNames[i]); +// prefix.append(' '); +// prefix.append(localVariableNames[i]); +// prefix.append(';'); +// } +// +// char[] fakeSource = CharOperation.concat(prefix.toString().toCharArray(), snippet, "}}".toCharArray());//$NON-NLS-1$ +// offset = prefix.length(); +// +// String encoding = JavaCore.getOption(JavaCore.CORE_ENCODING); +// BasicCompilationUnit fakeUnit = new BasicCompilationUnit( +// fakeSource, +// null, +// "FakeType.java", //$NON-NLS-1$ +// encoding); +// +// actualCompletionPosition = prefix.length() + position - 1; +// +// CompilationResult fakeResult = new CompilationResult(fakeUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit); +// CompilationUnitDeclaration fakeAST = parser.dietParse(fakeUnit, fakeResult, actualCompletionPosition); +// +// parseMethod(fakeAST, actualCompletionPosition); +// +// return (Initializer)fakeAST.types[0].fields[0]; +// } + + /** + * Ask the engine to compute a completion at the specified position + * of the given compilation unit. + * + * @return void + * completion results are answered through a requestor. + * + * @param sourceUnit net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit + * the source of the current compilation unit. + * + * @param completionPosition int + * a position in the source where the completion is taking place. + * This position is relative to the source provided. + */ + public void complete(ICompilationUnit sourceUnit, int completionPosition, int offset) { + + if(DEBUG) { + System.out.print("COMPLETION IN "); //$NON-NLS-1$ + System.out.print(sourceUnit.getFileName()); + System.out.print(" AT POSITION "); //$NON-NLS-1$ + System.out.println(completionPosition); + System.out.println("COMPLETION - Source :"); //$NON-NLS-1$ + System.out.println(sourceUnit.getContents()); + } + try { + actualCompletionPosition = completionPosition - 1; + this.offset = offset; + // for now until we can change the UI. + CompilationResult result = new CompilationResult(sourceUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = parser.dietParse(sourceUnit, result, actualCompletionPosition); + + // boolean completionNodeFound = false; + if (parsedUnit != null) { + if(DEBUG) { + System.out.println("COMPLETION - Diet AST :"); //$NON-NLS-1$ + System.out.println(parsedUnit.toString()); + } + + // scan the package & import statements first + if (parsedUnit.currentPackage instanceof CompletionOnPackageReference) { + findPackages((CompletionOnPackageReference) parsedUnit.currentPackage); + return; + } + + ImportReference[] imports = parsedUnit.imports; + if (imports != null) { + for (int i = 0, length = imports.length; i < length; i++) { + ImportReference importReference = imports[i]; + if (importReference instanceof CompletionOnImportReference) { + findImports((CompletionOnImportReference) importReference); + return; + } + } + } + + if (parsedUnit.types != null) { + try { + lookupEnvironment.buildTypeBindings(parsedUnit); + + if ((unitScope = parsedUnit.scope) != null) { + source = sourceUnit.getContents(); + lookupEnvironment.completeTypeBindings(parsedUnit, true); + parsedUnit.scope.faultInTypes(); + parseMethod(parsedUnit, actualCompletionPosition); + if(DEBUG) { + System.out.println("COMPLETION - AST :"); //$NON-NLS-1$ + System.out.println(parsedUnit.toString()); + } + parsedUnit.resolve(); + } + } catch (CompletionNodeFound e) { + // completionNodeFound = true; + if (e.astNode != null) { + if(DEBUG) { + System.out.print("COMPLETION - Completion node : "); //$NON-NLS-1$ + System.out.println(e.astNode.toString()); + } + // if null then we found a problem in the completion node + complete(e.astNode, e.qualifiedBinding, e.scope); + } + } + } + } + + /* Ignore package, import, class & interface keywords for now... + if (!completionNodeFound) { + if (parsedUnit == null || parsedUnit.types == null) { + // this is not good enough... can still be trying to define a second type + CompletionScanner scanner = (CompletionScanner) parser.scanner; + setSourceRange(scanner.completedIdentifierStart, scanner.completedIdentifierEnd); + findKeywords(scanner.completionIdentifier, mainDeclarations, null); + } + // currently have no way to know if extends/implements are possible keywords + } + */ + } catch (IndexOutOfBoundsException e) { // work-around internal failure - 1GEMF6D + } catch (InvalidCursorLocation e) { // may eventually report a usefull error + } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object + } catch (CompletionNodeFound e){ // internal failure - bugs 5618 + } finally { + reset(); + } + } + + private TypeBinding[] computeTypes(Expression[] arguments, BlockScope scope) { + + if (arguments == null) + return null; + + int argsLength = arguments.length; + TypeBinding[] argTypes = new TypeBinding[argsLength]; + for (int a = argsLength; --a >= 0;) + argTypes[a] = arguments[a].resolveType(scope); + return argTypes; + } + + private void findAnonymousType( + ReferenceBinding currentType, + TypeBinding[] argTypes, + Scope scope, + InvocationSite invocationSite) { + + if (currentType.isInterface()) { + char[] completion = TypeConstants.NoChar; + // nothing to insert - do not want to replace the existing selector & arguments + if (source == null + || source.length <= endPosition + || source[endPosition] != ')') + completion = new char[] { ')' }; + + requestor.acceptAnonymousType( + currentType.qualifiedPackageName(), + currentType.qualifiedSourceName(), + TypeConstants.NoCharChar, + TypeConstants.NoCharChar, + TypeConstants.NoCharChar, + completion, + IConstants.AccPublic, + endPosition - offset, + endPosition - offset, + R_DEFAULT); + } else { + findConstructors( + currentType, + argTypes, + scope, + invocationSite, + true); + } + } + + private void findClassField(char[] token, TypeBinding receiverType, Scope scope) { + + if (token == null) + return; + + if (token.length <= classField.length + && CharOperation.prefixEquals(token, classField, false /* ignore case */ + )) { + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(token, classField); + relevance += computeRelevanceForExpectingType(scope.getJavaLangClass()); + + requestor.acceptField( + NoChar, + NoChar, + classField, + NoChar, + NoChar, + classField, + CompilerModifiers.AccStatic | CompilerModifiers.AccPublic, + startPosition - offset, + endPosition - offset, + relevance); + } + } + + private void findConstructors( + ReferenceBinding currentType, + TypeBinding[] argTypes, + Scope scope, + InvocationSite invocationSite, + boolean forAnonymousType) { + + // No visibility checks can be performed without the scope & invocationSite + MethodBinding[] methods = currentType.availableMethods(); + if(methods != null) { + int minArgLength = argTypes == null ? 0 : argTypes.length; + next : for (int f = methods.length; --f >= 0;) { + MethodBinding constructor = methods[f]; + if (constructor.isConstructor()) { + + if (constructor.isSynthetic()) continue next; + + if (options.checkVisibility + && !constructor.canBeSeenBy(invocationSite, scope)) continue next; + + TypeBinding[] parameters = constructor.parameters; + int paramLength = parameters.length; + if (minArgLength > paramLength) + continue next; + for (int a = minArgLength; --a >= 0;) + if (argTypes[a] != null) // can be null if it could not be resolved properly + if (!scope.areTypesCompatible(argTypes[a], constructor.parameters[a])) + continue next; + + char[][] parameterPackageNames = new char[paramLength][]; + char[][] parameterTypeNames = new char[paramLength][]; + for (int i = 0; i < paramLength; i++) { + TypeBinding type = parameters[i]; + parameterPackageNames[i] = type.qualifiedPackageName(); + parameterTypeNames[i] = type.qualifiedSourceName(); + } + char[][] parameterNames = findMethodParameterNames(constructor,parameterTypeNames); + + char[] completion = TypeConstants.NoChar; + // nothing to insert - do not want to replace the existing selector & arguments + if (source == null + || source.length <= endPosition + || source[endPosition] != ')') + completion = new char[] { ')' }; + + if(forAnonymousType){ + requestor.acceptAnonymousType( + currentType.qualifiedPackageName(), + currentType.qualifiedSourceName(), + parameterPackageNames, + parameterTypeNames, + parameterNames, + completion, + constructor.modifiers, + endPosition - offset, + endPosition - offset, + R_DEFAULT); + } else { + requestor.acceptMethod( + currentType.qualifiedPackageName(), + currentType.qualifiedSourceName(), + currentType.sourceName(), + parameterPackageNames, + parameterTypeNames, + parameterNames, + TypeConstants.NoChar, + TypeConstants.NoChar, + completion, + constructor.modifiers, + endPosition - offset, + endPosition - offset, + R_DEFAULT); + } + } + } + } + } + + // Helper method for findFields(char[], ReferenceBinding, Scope, ObjectVector, boolean) + private void findFields( + char[] fieldName, + FieldBinding[] fields, + Scope scope, + ObjectVector fieldsFound, + ObjectVector localsFound, + boolean onlyStaticFields, + ReferenceBinding receiverType, + InvocationSite invocationSite, + Scope invocationScope, + boolean implicitCall) { + + // Inherited fields which are hidden by subclasses are filtered out + // No visibility checks can be performed without the scope & invocationSite + + int fieldLength = fieldName.length; + next : for (int f = fields.length; --f >= 0;) { + FieldBinding field = fields[f]; + + if (field.isSynthetic()) continue next; + + if (onlyStaticFields && !field.isStatic()) continue next; + + if (fieldLength > field.name.length) continue next; + + if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */)) continue next; + + if (options.checkVisibility + && !field.canBeSeenBy(receiverType, invocationSite, scope)) continue next; + + boolean prefixRequired = false; + + for (int i = fieldsFound.size; --i >= 0;) { + Object[] other = (Object[])fieldsFound.elementAt(i); + FieldBinding otherField = (FieldBinding) other[0]; + ReferenceBinding otherReceiverType = (ReferenceBinding) other[1]; + if (field == otherField && receiverType == otherReceiverType) + continue next; + if (CharOperation.equals(field.name, otherField.name, true)) { + if (field.declaringClass.isSuperclassOf(otherField.declaringClass)) + continue next; + if (otherField.declaringClass.isInterface()) + if (field.declaringClass.implementsInterface(otherField.declaringClass, true)) + continue next; + if (field.declaringClass.isInterface()) + if (otherField.declaringClass.implementsInterface(field.declaringClass, true)) + continue next; + prefixRequired = true; + } + } + + for (int l = localsFound.size; --l >= 0;) { + LocalVariableBinding local = (LocalVariableBinding) localsFound.elementAt(l); + + if (CharOperation.equals(field.name, local.name, true)) { + SourceTypeBinding declarationType = scope.enclosingSourceType(); + if (declarationType.isAnonymousType() && declarationType != invocationScope.enclosingSourceType()) { + continue next; + } + prefixRequired = true; + break; + } + } + + fieldsFound.add(new Object[]{field, receiverType}); + + char[] completion = field.name; + + if(prefixRequired || options.forceImplicitQualification){ + char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), field.isStatic()); + completion = CharOperation.concat(prefix,completion,'.'); + } + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(fieldName, field.name); + relevance += computeRelevanceForExpectingType(field.type); + + requestor + .acceptField( + field.declaringClass.qualifiedPackageName(), + field.declaringClass.qualifiedSourceName(), + field.name, + field.type.qualifiedPackageName(), + field.type.qualifiedSourceName(), + completion, + // may include some qualification to resolve ambiguities + field.modifiers, startPosition - offset, endPosition - offset, + relevance); + } + } + + private void findFields( + char[] fieldName, + ReferenceBinding receiverType, + Scope scope, + ObjectVector fieldsFound, + ObjectVector localsFound, + boolean onlyStaticFields, + InvocationSite invocationSite, + Scope invocationScope, + boolean implicitCall) { + + if (fieldName == null) + return; + + ReferenceBinding currentType = receiverType; + ReferenceBinding[][] interfacesToVisit = null; + int lastPosition = -1; + do { + + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + + if (interfacesToVisit == null) + interfacesToVisit = new ReferenceBinding[5][]; + + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + + FieldBinding[] fields = currentType.availableFields(); + if(fields != null) { + findFields( + fieldName, + fields, + scope, + fieldsFound, + localsFound, + onlyStaticFields, + receiverType, + invocationSite, + invocationScope, + implicitCall); + } + currentType = currentType.superclass(); + } while (currentType != null); + + if (interfacesToVisit != null) { + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + + ReferenceBinding anInterface = interfaces[j]; + if ((anInterface.tagBits & TagBits.InterfaceVisited) == 0) { + // if interface as not already been visited + anInterface.tagBits |= TagBits.InterfaceVisited; + + FieldBinding[] fields = anInterface.availableFields(); + if(fields != null) { + findFields( + fieldName, + fields, + scope, + fieldsFound, + localsFound, + onlyStaticFields, + receiverType, + invocationSite, + invocationScope, + implicitCall); + } + + ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~TagBits.InterfaceVisited; + } + } + } + + private void findFieldsAndMethods( + char[] token, + TypeBinding receiverType, + Scope scope, + InvocationSite invocationSite, + Scope invocationScope, + boolean implicitCall) { + + if (token == null) + return; + + if (receiverType.isBaseType()) + return; // nothing else is possible with base types + + if (receiverType.isArrayType()) { + if (token.length <= lengthField.length + && CharOperation.prefixEquals(token, lengthField, false /* ignore case */ + )) { + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(token,lengthField); + relevance += computeRelevanceForExpectingType(BaseTypes.IntBinding); + + requestor.acceptField( + NoChar, + NoChar, + lengthField, + NoChar, + NoChar, + lengthField, + CompilerModifiers.AccPublic, + startPosition - offset, + endPosition - offset, + relevance); + } + receiverType = scope.getJavaLangObject(); + } + + findFields( + token, + (ReferenceBinding) receiverType, + scope, + new ObjectVector(), + new ObjectVector(), + false, + invocationSite, + invocationScope, + implicitCall); + + findMethods( + token, + null, + (ReferenceBinding) receiverType, + scope, + new ObjectVector(), + false, + false, + false, + invocationSite, + invocationScope, + implicitCall); + } + + private void findImports(CompletionOnImportReference importReference) { + char[][] tokens = importReference.tokens; + + char[] importName = CharOperation.concatWith(tokens, '.'); + + if (importName.length == 0) + return; + + char[] lastToken = tokens[tokens.length - 1]; + if(lastToken != null && lastToken.length == 0) + importName = CharOperation.concat(importName, new char[]{'.'}); + + resolvingImports = true; + setSourceRange( + importReference.sourceStart, + importReference.declarationSourceEnd); + + token = importName; + // want to replace the existing .*; + nameEnvironment.findPackages(importName, this); + nameEnvironment.findTypes(importName, this); + } + + // what about onDemand types? Ignore them since it does not happen! + // import p1.p2.A.*; + private void findKeywords(char[] keyword, char[][] choices, Scope scope) { + + int length = keyword.length; + if (length > 0) + for (int i = 0; i < choices.length; i++) + if (length <= choices[i].length + && CharOperation.prefixEquals(keyword, choices[i], false /* ignore case */ + )){ + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(keyword, choices[i]); + + requestor.acceptKeyword(choices[i], startPosition - offset, endPosition - offset,relevance); + } + } + + // Helper method for findMemberTypes(char[], ReferenceBinding, Scope) + private void findMemberTypes( + char[] typeName, + ReferenceBinding[] memberTypes, + ObjectVector typesFound, + ReferenceBinding receiverType, + SourceTypeBinding invocationType) { + + // Inherited member types which are hidden by subclasses are filtered out + // No visibility checks can be performed without the scope & invocationSite + int typeLength = typeName.length; + next : for (int m = memberTypes.length; --m >= 0;) { + ReferenceBinding memberType = memberTypes[m]; + // if (!wantClasses && memberType.isClass()) continue next; + // if (!wantInterfaces && memberType.isInterface()) continue next; + if (typeLength > memberType.sourceName.length) + continue next; + + if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false + /* ignore case */ + )) + continue next; + + if (options.checkVisibility + && !memberType.canBeSeenBy(receiverType, invocationType)) + continue next; + + for (int i = typesFound.size; --i >= 0;) { + ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(i); + + if (memberType == otherType) + continue next; + + if (CharOperation.equals(memberType.sourceName, otherType.sourceName, true)) { + + if (memberType.enclosingType().isSuperclassOf(otherType.enclosingType())) + continue next; + + if (otherType.enclosingType().isInterface()) + if (memberType.enclosingType() + .implementsInterface(otherType.enclosingType(), true)) + continue next; + + if (memberType.enclosingType().isInterface()) + if (otherType.enclosingType() + .implementsInterface(memberType.enclosingType(), true)) + continue next; + } + } + + typesFound.add(memberType); + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName); + relevance += computeRelevanceForExpectingType(memberType); + + if (memberType.isClass()) { + relevance += computeRelevanceForClass(); + requestor.acceptClass( + memberType.qualifiedPackageName(), + memberType.qualifiedSourceName(), + memberType.sourceName(), + memberType.modifiers, + startPosition - offset, + endPosition - offset, + relevance); + + } else { + relevance += computeRelevanceForInterface(); + requestor.acceptInterface( + memberType.qualifiedPackageName(), + memberType.qualifiedSourceName(), + memberType.sourceName(), + memberType.modifiers, + startPosition - offset, + endPosition - offset, + relevance); + } + } + } + + private void findMemberTypes( + char[] typeName, + ReferenceBinding receiverType, + Scope scope, + SourceTypeBinding typeInvocation) { + + ReferenceBinding currentType = receiverType; + if (typeName == null) + return; + + if (currentType.superInterfaces() == null) + return; // we're trying to find a supertype + + ObjectVector typesFound = new ObjectVector(); + if (insideQualifiedReference + || typeName.length == 0) { // do not search up the hierarchy + + findMemberTypes( + typeName, + currentType.memberTypes(), + typesFound, + receiverType, + typeInvocation); + return; + } + + ReferenceBinding[][] interfacesToVisit = null; + int lastPosition = -1; + + do { + + ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + + if (interfacesToVisit == null) + interfacesToVisit = new ReferenceBinding[5][]; + + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + + findMemberTypes( + typeName, + currentType.memberTypes(), + typesFound, + receiverType, + typeInvocation); + currentType = currentType.superclass(); + + } while (currentType != null); + + if (interfacesToVisit != null) { + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + + ReferenceBinding anInterface = interfaces[j]; + if ((anInterface.tagBits & TagBits.InterfaceVisited) == 0) { + // if interface as not already been visited + anInterface.tagBits |= TagBits.InterfaceVisited; + + findMemberTypes( + typeName, + anInterface.memberTypes(), + typesFound, + receiverType, + typeInvocation); + + ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) + interfaces[j].tagBits &= ~TagBits.InterfaceVisited; + } + } + } + + private void findIntefacesMethods( + char[] selector, + TypeBinding[] argTypes, + ReferenceBinding receiverType, + ReferenceBinding[] itsInterfaces, + Scope scope, + ObjectVector methodsFound, + boolean onlyStaticMethods, + boolean exactMatch, + boolean isCompletingDeclaration, + InvocationSite invocationSite, + Scope invocationScope, + boolean implicitCall) { + + if (selector == null) + return; + + if (itsInterfaces != NoSuperInterfaces) { + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; + int lastPosition = 0; + interfacesToVisit[lastPosition] = itsInterfaces; + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding currentType = interfaces[j]; + + if ((currentType.tagBits & TagBits.InterfaceVisited) == 0) { + // if interface as not already been visited + currentType.tagBits |= TagBits.InterfaceVisited; + + MethodBinding[] methods = currentType.availableMethods(); + if(methods != null) { + if(isCompletingDeclaration){ + + findLocalMethodDeclarations( + selector, + methods, + scope, + methodsFound, + onlyStaticMethods, + exactMatch, + receiverType); + + } else { + + findLocalMethods( + selector, + argTypes, + methods, + scope, + methodsFound, + onlyStaticMethods, + exactMatch, + receiverType, + invocationSite, + invocationScope, + implicitCall); + } + } + + itsInterfaces = currentType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + + if (++lastPosition == interfacesToVisit.length) + System.arraycopy( + interfacesToVisit, + 0, + interfacesToVisit = new ReferenceBinding[lastPosition * 2][], + 0, + lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + + // bit reinitialization + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + + for (int j = 0, length = interfaces.length; j < length; j++){ + interfaces[j].tagBits &= ~TagBits.InterfaceVisited; + } + } + } + } + + private void findImplicitMessageSends( + char[] token, + TypeBinding[] argTypes, + Scope scope, + InvocationSite invocationSite, + Scope invocationScope) { + + if (token == null) + return; + + boolean staticsOnly = false; + // need to know if we're in a static context (or inside a constructor) + ObjectVector methodsFound = new ObjectVector(); + + done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + + switch (scope.kind) { + + case Scope.METHOD_SCOPE : + // handle the error case inside an explicit constructor call (see MethodScope>>findField) + MethodScope methodScope = (MethodScope) scope; + staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall; + break; + + case Scope.CLASS_SCOPE : + ClassScope classScope = (ClassScope) scope; + SourceTypeBinding enclosingType = classScope.referenceContext.binding; + findMethods( + token, + argTypes, + enclosingType, + classScope, + methodsFound, + staticsOnly, + true, + false, + invocationSite, + invocationScope, + true); + staticsOnly |= enclosingType.isStatic(); + break; + + case Scope.COMPILATION_UNIT_SCOPE : + break done; + } + scope = scope.parent; + } + } + + // Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean) + private void findLocalMethods( + char[] methodName, + TypeBinding[] argTypes, + MethodBinding[] methods, + Scope scope, + ObjectVector methodsFound, + boolean onlyStaticMethods, + boolean exactMatch, + ReferenceBinding receiverType, + InvocationSite invocationSite, + Scope invocationScope, + boolean implicitCall) { + + // Inherited methods which are hidden by subclasses are filtered out + // No visibility checks can be performed without the scope & invocationSite + + int methodLength = methodName.length; + int minArgLength = argTypes == null ? 0 : argTypes.length; + + next : for (int f = methods.length; --f >= 0;) { + MethodBinding method = methods[f]; + + if (method.isSynthetic()) continue next; + + if (method.isDefaultAbstract()) continue next; + + if (method.isConstructor()) continue next; + + // if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next; + if (onlyStaticMethods && !method.isStatic()) continue next; + + if (options.checkVisibility + && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue next; + + if (exactMatch) { + if (!CharOperation.equals(methodName, method.selector, false /* ignore case */ + )) + continue next; + + } else { + + if (methodLength > method.selector.length) + continue next; + + if (!CharOperation.prefixEquals(methodName, method.selector, false + /* ignore case */ + )) + continue next; + } + if (minArgLength > method.parameters.length) + continue next; + + for (int a = minArgLength; --a >= 0;){ + if (argTypes[a] != null){ // can be null if it could not be resolved properly + if (!scope.areTypesCompatible(argTypes[a], method.parameters[a])) { + continue next; + } + } + } + + boolean prefixRequired = false; + + for (int i = methodsFound.size; --i >= 0;) { + Object[] other = (Object[]) methodsFound.elementAt(i); + MethodBinding otherMethod = (MethodBinding) other[0]; + ReferenceBinding otherReceiverType = (ReferenceBinding) other[1]; + if (method == otherMethod && receiverType == otherReceiverType) + continue next; + + if (CharOperation.equals(method.selector, otherMethod.selector, true) + && method.areParametersEqual(otherMethod)) { + + if (method.declaringClass.isSuperclassOf(otherMethod.declaringClass)) + continue next; + + if (otherMethod.declaringClass.isInterface()) + if (method + .declaringClass + .implementsInterface(otherMethod.declaringClass, true)) + continue next; + + if (method.declaringClass.isInterface()) + if(otherMethod + .declaringClass + .implementsInterface(method.declaringClass,true)) + continue next; + prefixRequired = true; + } + } + + methodsFound.add(new Object[]{method, receiverType}); + int length = method.parameters.length; + char[][] parameterPackageNames = new char[length][]; + char[][] parameterTypeNames = new char[length][]; + + for (int i = 0; i < length; i++) { + TypeBinding type = method.parameters[i]; + parameterPackageNames[i] = type.qualifiedPackageName(); + parameterTypeNames[i] = type.qualifiedSourceName(); + } + char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames); + + char[] completion = TypeConstants.NoChar; + + int previousStartPosition = startPosition; + + // nothing to insert - do not want to replace the existing selector & arguments + if (!exactMatch) { + if (source != null + && source.length > endPosition + && source[endPosition] == '(') + completion = method.selector; + else + completion = CharOperation.concat(method.selector, new char[] { '(', ')' }); + } else { + if(prefixRequired && (source != null)) { + completion = CharOperation.subarray(source, startPosition, endPosition); + } else { + startPosition = endPosition; + } + } + + if(prefixRequired || options.forceImplicitQualification){ + char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), method.isStatic()); + completion = CharOperation.concat(prefix,completion,'.'); + } + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(methodName, method.selector); + relevance += computeRelevanceForExpectingType(method.returnType); + + requestor.acceptMethod( + method.declaringClass.qualifiedPackageName(), + method.declaringClass.qualifiedSourceName(), + method.selector, + parameterPackageNames, + parameterTypeNames, + parameterNames, + method.returnType.qualifiedPackageName(), + method.returnType.qualifiedSourceName(), + completion, + method.modifiers, + startPosition - offset, + endPosition - offset, + relevance); + startPosition = previousStartPosition; + } + } + + private int computeRelevanceForCaseMatching(char[] token, char[] proposalName){ + if (CharOperation.prefixEquals(token, proposalName, true /* do not ignore case */)) { + return R_CASE; + } else { + return R_DEFAULT; + } + } + private int computeRelevanceForClass(){ + if(assistNodeIsClass) { + return R_CLASS; + } + return 0; + } + private int computeRelevanceForInterface(){ + if(assistNodeIsInterface) { + return R_INTERFACE; + } + return R_DEFAULT; + } + private int computeRelevanceForException(char[] proposalName){ + + if(assistNodeIsException && + (CharOperation.match(EXCEPTION_PATTERN, proposalName, false) || + CharOperation.match(ERROR_PATTERN, proposalName, false))) { + return R_EXCEPTION; + } + return R_DEFAULT; + } + private int computeRelevanceForExpectingType(TypeBinding proposalType){ + if(expectedTypes != null && proposalType != null) { + for (int i = 0; i < expectedTypes.length; i++) { + if(Scope.areTypesCompatible(proposalType, expectedTypes[i])) { + return R_EXPECTED_TYPE; + } + } + } + return R_DEFAULT; + } + private int computeRelevanceForExpectingType(char[] packageName, char[] typeName){ + if(expectedTypes != null) { + for (int i = 0; i < expectedTypes.length; i++) { + if(CharOperation.equals(expectedTypes[i].qualifiedPackageName(), packageName) && + CharOperation.equals(expectedTypes[i].qualifiedSourceName(), typeName)) { + return R_EXPECTED_TYPE; + } + } + } + return R_DEFAULT; + } + + // Helper method for findMethods(char[], MethodBinding[], Scope, ObjectVector, boolean, boolean, boolean, TypeBinding) + private void findLocalMethodDeclarations( + char[] methodName, + MethodBinding[] methods, + Scope scope, + ObjectVector methodsFound, + // boolean noVoidReturnType, how do you know? + boolean onlyStaticMethods, + boolean exactMatch, + ReferenceBinding receiverType) { + + // Inherited methods which are hidden by subclasses are filtered out + // No visibility checks can be performed without the scope & invocationSite + int methodLength = methodName.length; + next : for (int f = methods.length; --f >= 0;) { + + MethodBinding method = methods[f]; + if (method.isSynthetic()) continue next; + + if (method.isDefaultAbstract()) continue next; + + if (method.isConstructor()) continue next; + + if (method.isFinal()) continue next; + + // if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next; + if (onlyStaticMethods && !method.isStatic()) continue next; + + if (options.checkVisibility + && !method.canBeSeenBy(receiverType, FakeInvocationSite , scope)) continue next; + + if (exactMatch) { + if (!CharOperation.equals(methodName, method.selector, false /* ignore case */ + )) + continue next; + + } else { + + if (methodLength > method.selector.length) + continue next; + + if (!CharOperation.prefixEquals(methodName, method.selector, false + /* ignore case */ + )) + continue next; + } + + for (int i = methodsFound.size; --i >= 0;) { + MethodBinding otherMethod = (MethodBinding) methodsFound.elementAt(i); + if (method == otherMethod) + continue next; + + if (CharOperation.equals(method.selector, otherMethod.selector, true) + && method.areParametersEqual(otherMethod)) { + continue next; + } + } + + methodsFound.add(method); + + int length = method.parameters.length; + char[][] parameterPackageNames = new char[length][]; + char[][] parameterTypeNames = new char[length][]; + + for (int i = 0; i < length; i++) { + TypeBinding type = method.parameters[i]; + parameterPackageNames[i] = type.qualifiedPackageName(); + parameterTypeNames[i] = type.qualifiedSourceName(); + } + + char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames); + + StringBuffer completion = new StringBuffer(10); + // flush uninteresting modifiers + int insertedModifiers = method.modifiers & ~(CompilerModifiers.AccNative | CompilerModifiers.AccAbstract); + + if (!exactMatch) { + if(insertedModifiers != CompilerModifiers.AccDefault){ + completion.append(AstNode.modifiersString(insertedModifiers)); + } + char[] returnPackageName = method.returnType.qualifiedPackageName(); + char[] returnTypeName = method.returnType.qualifiedSourceName(); + if(mustQualifyType(returnPackageName, returnTypeName)) { + completion.append(CharOperation.concat(returnPackageName, returnTypeName,'.')); + } else { + completion.append(method.returnType.sourceName()); + } + completion.append(' '); + completion.append(method.selector); + completion.append('('); + + for(int i = 0; i < length ; i++){ + if(mustQualifyType(parameterPackageNames[i], parameterTypeNames[i])){ + completion.append(CharOperation.concat(parameterPackageNames[i], parameterTypeNames[i], '.')); + } else { + completion.append(parameterTypeNames[i]); + } + completion.append(' '); + if(parameterNames != null){ + completion.append(parameterNames[i]); + } else { + completion.append('%'); + } + if(i != (length - 1)) + completion.append(','); + } + completion.append(')'); + + ReferenceBinding[] exceptions = method.thrownExceptions; + + if (exceptions != null && exceptions.length > 0){ + completion.append(' '); + completion.append(THROWS); + completion.append(' '); + for(int i = 0; i < exceptions.length ; i++){ + ReferenceBinding exception = exceptions[i]; + + char[] exceptionPackageName = exception.qualifiedPackageName(); + char[] exceptionTypeName = exception.qualifiedSourceName(); + + if(i != 0){ + completion.append(','); + completion.append(' '); + } + + if(mustQualifyType(exceptionPackageName, exceptionTypeName)){ + completion.append(CharOperation.concat(exceptionPackageName, exceptionTypeName, '.')); + } else { + completion.append(exception.sourceName()); + } + } + } + } + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(methodName, method.selector); + + requestor.acceptMethodDeclaration( + method.declaringClass.qualifiedPackageName(), + method.declaringClass.qualifiedSourceName(), + method.selector, + parameterPackageNames, + parameterTypeNames, + parameterNames, + method.returnType.qualifiedPackageName(), + method.returnType.qualifiedSourceName(), + completion.toString().toCharArray(), + method.modifiers, + startPosition - offset, + endPosition - offset, + relevance); + } + } + private void findMethods( + char[] selector, + TypeBinding[] argTypes, + ReferenceBinding receiverType, + Scope scope, + ObjectVector methodsFound, + boolean onlyStaticMethods, + boolean exactMatch, + boolean isCompletingDeclaration, + InvocationSite invocationSite, + Scope invocationScope, + boolean implicitCall) { + if (selector == null) + return; + + if(isCompletingDeclaration) { + MethodBinding[] methods = receiverType.availableMethods(); + if (methods != null){ + for (int i = 0; i < methods.length; i++) { + if(!methods[i].isDefaultAbstract()) { + methodsFound.add(methods[i]); + } + } + } + } + + ReferenceBinding currentType = receiverType; + if (receiverType.isInterface()) { + if(isCompletingDeclaration) { + findIntefacesMethods( + selector, + argTypes, + receiverType, + currentType.superInterfaces(), + scope, + methodsFound, + onlyStaticMethods, + exactMatch, + isCompletingDeclaration, + invocationSite, + invocationScope, + implicitCall); + } else { + findIntefacesMethods( + selector, + argTypes, + receiverType, + new ReferenceBinding[]{currentType}, + scope, + methodsFound, + onlyStaticMethods, + exactMatch, + isCompletingDeclaration, + invocationSite, + invocationScope, + implicitCall); + } + + currentType = scope.getJavaLangObject(); + } else { + if(isCompletingDeclaration){ + findIntefacesMethods( + selector, + argTypes, + receiverType, + currentType.superInterfaces(), + scope, + methodsFound, + onlyStaticMethods, + exactMatch, + isCompletingDeclaration, + invocationSite, + invocationScope, + implicitCall); + + currentType = receiverType.superclass(); + } + } + boolean hasPotentialDefaultAbstractMethods = true; + while (currentType != null) { + + MethodBinding[] methods = currentType.availableMethods(); + if(methods != null) { + if(isCompletingDeclaration){ + findLocalMethodDeclarations( + selector, + methods, + scope, + methodsFound, + onlyStaticMethods, + exactMatch, + receiverType); + } else{ + findLocalMethods( + selector, + argTypes, + methods, + scope, + methodsFound, + onlyStaticMethods, + exactMatch, + receiverType, + invocationSite, + invocationScope, + implicitCall); + } + } + + if(hasPotentialDefaultAbstractMethods && currentType.isAbstract()){ + findIntefacesMethods( + selector, + argTypes, + receiverType, + currentType.superInterfaces(), + scope, + methodsFound, + onlyStaticMethods, + exactMatch, + isCompletingDeclaration, + invocationSite, + invocationScope, + implicitCall); + } else { + hasPotentialDefaultAbstractMethods = false; + } + currentType = currentType.superclass(); + } + } + private char[][] findMethodParameterNames(MethodBinding method, char[][] parameterTypeNames){ + ReferenceBinding bindingType = method.declaringClass; + + char[][] parameterNames = null; + + int length = parameterTypeNames.length; + + if (length == 0){ + return TypeConstants.NoCharChar; + } + // look into the corresponding unit if it is available + if (bindingType instanceof SourceTypeBinding){ + SourceTypeBinding sourceType = (SourceTypeBinding) bindingType; + + if (sourceType.scope != null){ + TypeDeclaration parsedType; + + if ((parsedType = sourceType.scope.referenceContext) != null){ + AbstractMethodDeclaration methodDecl = parsedType.declarationOf(method); + + if (methodDecl != null){ + Argument[] arguments = methodDecl.arguments; + parameterNames = new char[length][]; + + for(int i = 0 ; i < length ; i++){ + parameterNames[i] = arguments[i].name; + } + } + } + } + } + // look into the model + if(parameterNames == null){ + NameEnvironmentAnswer answer = nameEnvironment.findType(bindingType.compoundName); + + if(answer != null){ + if(answer.isSourceType()) { + ISourceType sourceType = answer.getSourceTypes()[0]; + ISourceMethod[] sourceMethods = sourceType.getMethods(); + int len = sourceMethods == null ? 0 : sourceMethods.length; + for(int i = 0; i < len ; i++){ + ISourceMethod sourceMethod = sourceMethods[i]; + char[][] argTypeNames = sourceMethod.getArgumentTypeNames(); + + if(argTypeNames != null && + CharOperation.equals(method.selector,sourceMethod.getSelector()) && + CharOperation.equals(argTypeNames,parameterTypeNames)){ + parameterNames = sourceMethod.getArgumentNames(); + break; + } + } + } + } + } + return parameterNames; + } + + private void findNestedTypes( + char[] typeName, + SourceTypeBinding currentType, + Scope scope) { + if (typeName == null) + return; + + int typeLength = typeName.length; + + while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found + + switch (scope.kind) { + + case Scope.METHOD_SCOPE : + case Scope.BLOCK_SCOPE : + BlockScope blockScope = (BlockScope) scope; + + next : for (int i = 0, length = blockScope.scopeIndex; i < length; i++) { + + if (blockScope.subscopes[i] instanceof ClassScope) { + SourceTypeBinding localType = + ((ClassScope) blockScope.subscopes[i]).referenceContext.binding; + + if (!localType.isAnonymousType()) { + if (typeLength > localType.sourceName.length) + continue next; + if (!CharOperation.prefixEquals(typeName, localType.sourceName, false + /* ignore case */ + )) + continue next; + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(typeName, localType.sourceName); + relevance += computeRelevanceForExpectingType(localType); + relevance += computeRelevanceForClass(); + + requestor.acceptClass( + localType.qualifiedPackageName(), + localType.sourceName, + localType.sourceName, + localType.modifiers, + startPosition - offset, + endPosition - offset, + relevance); + } + } + } + break; + + case Scope.CLASS_SCOPE : + findMemberTypes(typeName, scope.enclosingSourceType(), scope, currentType); + if (typeLength == 0) + return; // do not search outside the class scope if no prefix was provided + break; + + case Scope.COMPILATION_UNIT_SCOPE : + return; + } + scope = scope.parent; + } + } + + private void findPackages(CompletionOnPackageReference packageStatement) { + + token = CharOperation.concatWith(packageStatement.tokens, '.'); + if (token.length == 0) + return; + + setSourceRange(packageStatement.sourceStart, packageStatement.sourceEnd); + nameEnvironment.findPackages(CharOperation.toLowerCase(token), this); + } + + private void findTypesAndPackages(char[] token, Scope scope) { + + if (token == null) + return; + + if (scope.enclosingSourceType() != null) + findNestedTypes(token, scope.enclosingSourceType(), scope); + + if (unitScope != null) { + int typeLength = token.length; + SourceTypeBinding[] types = unitScope.topLevelTypes; + + for (int i = 0, length = types.length; i < length; i++) { + SourceTypeBinding sourceType = types[i]; + + if (typeLength > sourceType.sourceName.length) continue; + + if (!CharOperation.prefixEquals(token, sourceType.sourceName, false)) continue; + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(token, sourceType.sourceName); + relevance += computeRelevanceForExpectingType(sourceType); + + if (sourceType.isClass()){ + relevance += computeRelevanceForClass(); + requestor.acceptClass( + sourceType.qualifiedPackageName(), + sourceType.sourceName(), + sourceType.sourceName(), + sourceType.modifiers, + startPosition - offset, + endPosition - offset, + relevance); + } else { + relevance += computeRelevanceForInterface(); + requestor.acceptInterface( + sourceType.qualifiedPackageName(), + sourceType.sourceName(), + sourceType.sourceName(), + sourceType.modifiers, + startPosition - offset, + endPosition - offset, + relevance); + } + } + } + + if (token.length == 0) + return; + + findKeywords(token, baseTypes, scope); + nameEnvironment.findTypes(token, this); + nameEnvironment.findPackages(token, this); + } + + private void findTypesAndSubpackages( + char[] token, + PackageBinding packageBinding) { + + char[] qualifiedName = + CharOperation.concatWith(packageBinding.compoundName, token, '.'); + + if (token == null || token.length == 0) { + int length = qualifiedName.length; + System.arraycopy( + qualifiedName, + 0, + qualifiedName = new char[length + 1], + 0, + length); + qualifiedName[length] = '.'; + } + nameEnvironment.findTypes(qualifiedName, this); + nameEnvironment.findPackages(qualifiedName, this); + } + + private void findVariablesAndMethods( + char[] token, + Scope scope, + InvocationSite invocationSite, + Scope invocationScope) { + + if (token == null) + return; + + // Should local variables hide fields from the receiver type or any of its enclosing types? + // we know its an implicit field/method access... see BlockScope getBinding/getImplicitMethod + + boolean staticsOnly = false; + // need to know if we're in a static context (or inside a constructor) + int tokenLength = token.length; + + ObjectVector localsFound = new ObjectVector(); + ObjectVector fieldsFound = new ObjectVector(); + ObjectVector methodsFound = new ObjectVector(); + + Scope currentScope = scope; + + done1 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + + switch (currentScope.kind) { + + case Scope.METHOD_SCOPE : + // handle the error case inside an explicit constructor call (see MethodScope>>findField) + MethodScope methodScope = (MethodScope) currentScope; + staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall; + + case Scope.BLOCK_SCOPE : + BlockScope blockScope = (BlockScope) currentScope; + + next : for (int i = 0, length = blockScope.locals.length; i < length; i++) { + LocalVariableBinding local = blockScope.locals[i]; + + if (local == null) + break next; + + if (tokenLength > local.name.length) + continue next; + + if (!CharOperation.prefixEquals(token, local.name, false /* ignore case */ + )) + continue next; + + if (local.isSecret()) + continue next; + + for (int f = 0; f < localsFound.size; f++) { + LocalVariableBinding otherLocal = + (LocalVariableBinding) localsFound.elementAt(f); + if (CharOperation.equals(otherLocal.name, local.name, true)) + continue next; + } + localsFound.add(local); + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(token, local.name); + relevance += computeRelevanceForExpectingType(local.type); + + requestor.acceptLocalVariable( + local.name, + local.type == null + ? NoChar + : local.type.qualifiedPackageName(), + local.type == null + ? local.declaration.type.toString().toCharArray() + : local.type.qualifiedSourceName(), + local.modifiers, + startPosition - offset, + endPosition - offset, + relevance); + } + break; + + case Scope.COMPILATION_UNIT_SCOPE : + break done1; + } + currentScope = currentScope.parent; + } + + currentScope = scope; + + done2 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + + switch (currentScope.kind) { + + case Scope.CLASS_SCOPE : + ClassScope classScope = (ClassScope) currentScope; + SourceTypeBinding enclosingType = classScope.referenceContext.binding; + /* if (tokenLength == 0) { // only search inside the type itself if no prefix was provided + findFields(token, enclosingType.fields(), classScope, fieldsFound, staticsOnly); + findMethods(token, enclosingType.methods(), classScope, methodsFound, staticsOnly, false); + break done; + } else { */ + findFields( + token, + enclosingType, + classScope, + fieldsFound, + localsFound, + staticsOnly, + invocationSite, + invocationScope, + true); + + findMethods( + token, + null, + enclosingType, + classScope, + methodsFound, + staticsOnly, + false, + false, + invocationSite, + invocationScope, + true); + staticsOnly |= enclosingType.isStatic(); + // } + break; + + case Scope.COMPILATION_UNIT_SCOPE : + break done2; + } + currentScope = currentScope.parent; + } + } + + // Helper method for private void findVariableNames(char[] name, TypeReference type ) + private void findVariableName(char[] token, char[] qualifiedPackageName, char[] qualifiedSourceName, char[] sourceName, char[][] excludeNames, int dim){ + if(sourceName == null || sourceName.length == 0) + return; + + char[] name = null; + + // compute variable name for base type + try{ + nameScanner.setSource(sourceName); + nameScanner.getNextToken(); // switch (nameScanner.getNextToken()) { +// case TokenNameint : +// case TokenNamebyte : +// case TokenNameshort : +// case TokenNamechar : +// case TokenNamelong : +// case TokenNamefloat : +// case TokenNamedouble : +// case TokenNameboolean : +// if(token != null && token.length != 0) +// return; +// name = computeBaseNames(sourceName[0], excludeNames); +// break; +// } + if(name != null) { + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(token, name); + + // accept result + requestor.acceptVariableName( + qualifiedPackageName, + qualifiedSourceName, + name, + name, + startPosition - offset, + endPosition - offset, + relevance); + return; + } + } catch(InvalidInputException e){ + } + + // compute variable name for non base type + char[][] names = computeNames(sourceName, dim > 0); + char[] displayName; + if (dim > 0){ + int l = qualifiedSourceName.length; + displayName = new char[l+(2*dim)]; + System.arraycopy(qualifiedSourceName, 0, displayName, 0, l); + for(int i = 0; i < dim; i++){ + displayName[l+(i*2)] = '['; + displayName[l+(i*2)+1] = ']'; + } + } else { + displayName = qualifiedSourceName; + } + next : for(int i = 0 ; i < names.length ; i++){ + name = names[i]; + + if (!CharOperation.prefixEquals(token, name, false)) + continue next; + + // completion must be an identifier (not a keyword, ...). + try{ + nameScanner.setSource(name); + if(nameScanner.getNextToken() != TokenNameIdentifier) + continue next; + } catch(InvalidInputException e){ + continue next; + } + + int count = 2; + char[] originalName = name; + for(int j = 0 ; j < excludeNames.length ; j++){ + if(CharOperation.equals(name, excludeNames[j], false)) { + name = CharOperation.concat(originalName, String.valueOf(count++).toCharArray()); + j = 0; + } + } + + int relevance = R_DEFAULT; + relevance += computeRelevanceForCaseMatching(token, name); + + // accept result + requestor.acceptVariableName( + qualifiedPackageName, + displayName, + name, + name, + startPosition - offset, + endPosition - offset, + relevance); + } + } + + private void findVariableNames(char[] name, TypeReference type , char[][] excludeNames){ + + if(type != null && + type.binding != null && + type.binding.problemId() == Binding.NoError){ + TypeBinding tb = type.binding; + findVariableName( + name, + tb.leafComponentType().qualifiedPackageName(), + tb.leafComponentType().qualifiedSourceName(), + tb.leafComponentType().sourceName(), + excludeNames, + type.dimensions()); + }/* else { + char[][] typeName = type.getTypeName(); + findVariableName( + name, + NoChar, + CharOperation.concatWith(typeName, '.'), + typeName[typeName.length - 1], + excludeNames, + type.dimensions()); + }*/ + } + + public AssistParser getParser() { + + return parser; + } + + protected void reset() { + + super.reset(); + this.knownPkgs = new HashtableOfObject(10); + this.knownTypes = new HashtableOfObject(10); + } + + private void setSourceRange(int start, int end) { + + this.startPosition = start; + this.endPosition = end + 1; + } + + private char[] computeBaseNames(char firstName, char[][] excludeNames){ + char[] name = new char[]{firstName}; + + for(int i = 0 ; i < excludeNames.length ; i++){ + if(CharOperation.equals(name, excludeNames[i], false)) { + name[0]++; + if(name[0] > 'z') + name[0] = 'a'; + if(name[0] == firstName) + return null; + i = 0; + } + } + + return name; + } + private void computeExpectedTypes(AstNode parent, Scope scope){ + int expectedTypeCount = 0; + expectedTypes = new TypeBinding[1]; + + if(parent instanceof AbstractVariableDeclaration) { + TypeBinding binding = ((AbstractVariableDeclaration)parent).type.binding; + if(binding != null) { + expectedTypes[expectedTypeCount++] = binding; + } + } else if(parent instanceof Assignment) { + TypeBinding binding = ((Assignment)parent).lhsType; + if(binding != null) { + expectedTypes[expectedTypeCount++] = binding; + } + } else if(parent instanceof ReturnStatement) { + MethodBinding methodBinding = ((AbstractMethodDeclaration) scope.methodScope().referenceContext).binding; + TypeBinding binding = methodBinding == null ? null : methodBinding.returnType; + if(binding != null) { + expectedTypes[expectedTypeCount++] = binding; + } + } + + System.arraycopy(expectedTypes, 0, expectedTypes = new TypeBinding[expectedTypeCount], 0, expectedTypeCount); + } + private char[][] computeNames(char[] sourceName, boolean forArray){ + char[][] names = new char[5][]; + int nameCount = 0; + boolean previousIsUpperCase = false; + for(int i = sourceName.length - 1 ; i >= 0 ; i--){ + boolean isUpperCase = Character.isUpperCase(sourceName[i]); + if(isUpperCase && !previousIsUpperCase){ + char[] name = CharOperation.subarray(sourceName,i,sourceName.length); + if(name.length > 1){ + if(nameCount == names.length) { + System.arraycopy(names, 0, names = new char[nameCount * 2][], 0, nameCount); + } + name[0] = Character.toLowerCase(name[0]); + + if(forArray) { + int length = name.length; + if (name[length-1] == 's'){ + System.arraycopy(name, 0, name = new char[length + 2], 0, length); + name[length] = 'e'; + name[length+1] = 's'; + } else { + System.arraycopy(name, 0, name = new char[length + 1], 0, length); + name[length] = 's'; + } + } + names[nameCount++] = name; + } + } + previousIsUpperCase = isUpperCase; + } + if(nameCount == 0){ + char[] name = CharOperation.toLowerCase(sourceName); + if(forArray) { + int length = name.length; + if (name[length-1] == 's'){ + System.arraycopy(name, 0, name = new char[length + 2], 0, length); + name[length] = 'e'; + name[length+1] = 's'; + } else { + System.arraycopy(name, 0, name = new char[length + 1], 0, length); + name[length] = 's'; + } + } + names[nameCount++] = name; + + } + System.arraycopy(names, 0, names = new char[nameCount][], 0, nameCount); + return names; + } + + private char[] computePrefix(SourceTypeBinding declarationType, SourceTypeBinding invocationType, boolean isStatic){ + + StringBuffer completion = new StringBuffer(10); + + if (isStatic) { + completion.append(declarationType.sourceName()); + + } else if (declarationType == invocationType) { + completion.append(THIS); + + } else { + + if (!declarationType.isNestedType()) { + + completion.append(declarationType.sourceName()); + completion.append('.'); + completion.append(THIS); + + } else if (!declarationType.isAnonymousType()) { + + completion.append(declarationType.sourceName()); + completion.append('.'); + completion.append(THIS); + + } + } + + return completion.toString().toCharArray(); + } + + private boolean isEnclosed(ReferenceBinding possibleEnclosingType, ReferenceBinding type){ + if(type.isNestedType()){ + ReferenceBinding enclosing = type.enclosingType(); + while(enclosing != null ){ + if(possibleEnclosingType == enclosing) + return true; + enclosing = enclosing.enclosingType(); + } + } + return false; + } + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/ISearchRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/ISearchRequestor.java new file mode 100644 index 0000000..a7ddb3a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/ISearchRequestor.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist; + +/** + * This is the internal requestor passed to the searchable name environment + * so as to process the multiple search results as they are discovered. + * + * It is used to allow the code assist engine to add some more information + * to the raw name environment results before answering them to the UI. + */ +public interface ISearchRequestor { + + /** + * One result of the search consists of a new class. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ + public void acceptClass(char[] packageName, char[] typeName, int modifiers); + + /** + * One result of the search consists of a new interface. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.I". + * The default package is represented by an empty array. + */ + public void acceptInterface(char[] packageName, char[] typeName, int modifiers); + + /** + * One result of the search consists of a new package. + * + * NOTE - All package names are presented in their readable form: + * Package names are in the form "a.b.c". + * The default package is represented by an empty array. + */ + public void acceptPackage(char[] packageName); + + /** + * One result of the search consists of a new type. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ + public void acceptType(char[] packageName, char[] typeName); +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/ISearchableNameEnvironment.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/ISearchableNameEnvironment.java new file mode 100644 index 0000000..3bd46bf --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/ISearchableNameEnvironment.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist; + +import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment; + +/** + * This interface defines the API that may be used to implement any + * search-based tool (such as a CodeAssist, a Finder, ...). + * It is mainly used to hide from the search tool the implementation + * of the underlying environment and its constructions. + */ +public interface ISearchableNameEnvironment extends INameEnvironment { + + /** + * Find the packages that start with the given prefix. + * A valid prefix is a qualified name separated by periods + * (ex. java.util). + * The packages found are passed to: + * ISearchRequestor.acceptPackage(char[][] packageName) + */ + void findPackages(char[] prefix, ISearchRequestor requestor); + + /** + * Find the top-level types (classes and interfaces) that are defined + * in the current environment and whose name starts with the + * given prefix. The prefix is a qualified name separated by periods + * or a simple name (ex. java.util.V or V). + * + * The types found are passed to one of the following methods (if additional + * information is known about the types): + * ISearchRequestor.acceptType(char[][] packageName, char[] typeName) + * ISearchRequestor.acceptClass(char[][] packageName, char[] typeName, int modifiers) + * ISearchRequestor.acceptInterface(char[][] packageName, char[] typeName, int modifiers) + * + * This method can not be used to find member types... member + * types are found relative to their enclosing type. + */ + void findTypes(char[] prefix, ISearchRequestor requestor); +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/ISelectionRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/ISelectionRequestor.java new file mode 100644 index 0000000..b8384a5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/ISelectionRequestor.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist; + +import net.sourceforge.phpdt.core.compiler.IProblem; + +/** + * A selection requestor accepts results from the selection engine. + */ +public interface ISelectionRequestor { + /** + * Code assist notification of a class selection. + * @param packageName char[] + * Declaring package name of the class. + * + * @param className char[] + * Name of the class. + * + * @param needQualification boolean + * Flag indicating if the type name + * must be qualified by its package name (depending on imports). + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ + void acceptClass( + char[] packageName, + char[] className, + boolean needQualification); + + /** + * Code assist notification of a compilation error detected during selection. + * @param error net.sourceforge.phpdt.internal.compiler.IProblem + * Only problems which are categorized as errors are notified to the requestor, + * warnings are silently ignored. + * In case an error got signaled, no other completions might be available, + * therefore the problem message should be presented to the user. + * The source positions of the problem are related to the source where it was + * detected (might be in another compilation unit, if it was indirectly requested + * during the code assist process). + * Note: the problem knows its originating file name. + */ + void acceptError(IProblem error); + + /** + * Code assist notification of a field selection. + * @param declaringTypePackageName char[] + * Name of the package in which the type that contains this field is declared. + * + * @param declaringTypeName char[] + * Name of the type declaring this new field. + * + * @param name char[] + * Name of the field. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ + void acceptField( + char[] declaringTypePackageName, + char[] declaringTypeName, + char[] name); + + /** + * Code assist notification of an interface selection. + * @param packageName char[] + * Declaring package name of the interface. + * + * @param interfaceName char[] + * Name of the interface. + * + * @param needQualification boolean + * Flag indicating if the type name + * must be qualified by its package name (depending on imports). + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.I". + * The default package is represented by an empty array. + */ + void acceptInterface( + char[] packageName, + char[] interfaceName, + boolean needQualification); + + /** + * Code assist notification of a method selection. + * @param declaringTypePackageName char[] + * Name of the package in which the type that contains this new method is declared. + * + * @param declaringTypeName char[] + * Name of the type declaring this new method. + * + * @param selector char[] + * Name of the new method. + * + * @param parameterPackageNames char[][] + * Names of the packages in which the parameter types are declared. + * Should contain as many elements as parameterTypeNames. + * + * @param parameterTypeNames char[][] + * Names of the parameters types. + * Should contain as many elements as parameterPackageNames. + * + * @param isConstructor boolean + * Answer if the method is a constructor. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Base types are in the form "int" or "boolean". + * Array types are in the qualified form "M[]" or "int[]". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ + void acceptMethod( + char[] declaringTypePackageName, + char[] declaringTypeName, + char[] selector, + char[][] parameterPackageNames, + char[][] parameterTypeNames, + boolean isConstructor); + + /** + * Code assist notification of a package selection. + * @param packageName char[] + * The package name. + * + * NOTE - All package names are presented in their readable form: + * Package names are in the form "a.b.c". + * The default package is represented by an empty array. + */ + void acceptPackage(char[] packageName); +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/RelevanceConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/RelevanceConstants.java new file mode 100644 index 0000000..1c00a85 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/RelevanceConstants.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist; + +public interface RelevanceConstants { + + int R_DEFAULT = 0; + int R_CASE = 10; + int R_EXPECTED_TYPE = 20; + int R_INTERFACE = 20; + int R_CLASS = 20; + int R_EXCEPTION = 20; +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/SelectionEngine.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/SelectionEngine.java new file mode 100644 index 0000000..6f5e306 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/SelectionEngine.java @@ -0,0 +1,739 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist; + +import java.util.*; + +import net.sourceforge.phpdt.core.compiler.*; +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.internal.codeassist.impl.*; +import net.sourceforge.phpdt.internal.codeassist.select.*; +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.env.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.*; +import net.sourceforge.phpdt.internal.compiler.impl.*; + +/** + * The selection engine is intended to infer the nature of a selected name in some + * source code. This name can be qualified. + * + * Selection is resolving context using a name environment (no need to search), assuming + * the source where selection occurred is correct and will not perform any completion + * attempt. If this was the desired behavior, a call to the CompletionEngine should be + * performed instead. + */ +public final class SelectionEngine extends Engine implements ISearchRequestor { + + public static boolean DEBUG = false; + + SelectionParser parser; + ISelectionRequestor requestor; + + boolean acceptedAnswer; + + private int actualSelectionStart; + private int actualSelectionEnd; + private char[] qualifiedSelection; + private char[] selectedIdentifier; + + private char[][][] acceptedClasses; + private char[][][] acceptedInterfaces; + int acceptedClassesCount; + int acceptedInterfacesCount; + + /** + * The SelectionEngine is responsible for computing the selected object. + * + * It requires a searchable name environment, which supports some + * specific search APIs, and a requestor to feed back the results to a UI. + * + * @param nameEnvironment net.sourceforge.phpdt.internal.codeassist.ISearchableNameEnvironment + * used to resolve type/package references and search for types/packages + * based on partial names. + * + * @param requestor net.sourceforge.phpdt.internal.codeassist.ISelectionRequestor + * since the engine might produce answers of various forms, the engine + * is associated with a requestor able to accept all possible completions. + * + * @param settings java.util.Map + * set of options used to configure the code assist engine. + */ + public SelectionEngine( + ISearchableNameEnvironment nameEnvironment, + ISelectionRequestor requestor, + Map settings) { + + super(settings); + + this.requestor = requestor; + this.nameEnvironment = nameEnvironment; + + ProblemReporter problemReporter = + new ProblemReporter( + DefaultErrorHandlingPolicies.proceedWithAllProblems(), + this.compilerOptions, + new DefaultProblemFactory(Locale.getDefault())) { + public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) { + unitResult.record(problem, referenceContext); + SelectionEngine.this.requestor.acceptError(problem); + } + }; + this.parser = new SelectionParser(problemReporter, this.compilerOptions.assertMode); + this.lookupEnvironment = + new LookupEnvironment(this, this.compilerOptions, problemReporter, nameEnvironment); + } + + /** + * One result of the search consists of a new class. + * @param packageName char[] + * @param className char[] + * @param modifiers int + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ + public void acceptClass(char[] packageName, char[] className, int modifiers) { + if (CharOperation.equals(className, selectedIdentifier)) { + if (qualifiedSelection != null + && !CharOperation.equals( + qualifiedSelection, + CharOperation.concat(packageName, className, '.'))) { + return; + } + + if(mustQualifyType(packageName, className)) { + char[][] acceptedClass = new char[2][]; + acceptedClass[0] = packageName; + acceptedClass[1] = className; + + if(acceptedClasses == null) { + acceptedClasses = new char[10][][]; + acceptedClassesCount = 0; + } + int length = acceptedClasses.length; + if(length == acceptedClassesCount) { + System.arraycopy(acceptedClasses, 0, acceptedClasses = new char[(length + 1)* 2][][], 0, length); + } + acceptedClasses[acceptedClassesCount++] = acceptedClass; + + } else { + requestor.acceptClass( + packageName, + className, + false); + acceptedAnswer = true; + } + } + } + + /** + * One result of the search consists of a new interface. + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.I". + * The default package is represented by an empty array. + */ + public void acceptInterface( + char[] packageName, + char[] interfaceName, + int modifiers) { + + if (CharOperation.equals(interfaceName, selectedIdentifier)) { + if (qualifiedSelection != null + && !CharOperation.equals( + qualifiedSelection, + CharOperation.concat(packageName, interfaceName, '.'))) { + return; + } + + if(mustQualifyType(packageName, interfaceName)) { + char[][] acceptedInterface= new char[2][]; + acceptedInterface[0] = packageName; + acceptedInterface[1] = interfaceName; + + if(acceptedInterfaces == null) { + acceptedInterfaces = new char[10][][]; + acceptedInterfacesCount = 0; + } + int length = acceptedInterfaces.length; + if(length == acceptedInterfacesCount) { + System.arraycopy(acceptedInterfaces, 0, acceptedInterfaces = new char[(length + 1) * 2][][], 0, length); + } + acceptedInterfaces[acceptedInterfacesCount++] = acceptedInterface; + + } else { + requestor.acceptInterface( + packageName, + interfaceName, + false); + acceptedAnswer = true; + } + } + } + + /** + * One result of the search consists of a new package. + * @param packageName char[] + * + * NOTE - All package names are presented in their readable form: + * Package names are in the form "a.b.c". + * The default package is represented by an empty array. + */ + public void acceptPackage(char[] packageName) { + } + + private void acceptQualifiedTypes() { + if(acceptedClasses != null){ + acceptedAnswer = true; + for (int i = 0; i < acceptedClassesCount; i++) { + requestor.acceptClass( + acceptedClasses[i][0], + acceptedClasses[i][1], + true); + } + acceptedClasses = null; + acceptedClassesCount = 0; + } + if(acceptedInterfaces != null){ + acceptedAnswer = true; + for (int i = 0; i < acceptedInterfacesCount; i++) { + requestor.acceptInterface( + acceptedInterfaces[i][0], + acceptedInterfaces[i][1], + true); + } + acceptedInterfaces = null; + acceptedInterfacesCount = 0; + } + } + + /** + * One result of the search consists of a new type. + * @param packageName char[] + * @param typeName char[] + * + * NOTE - All package and type names are presented in their readable form: + * Package names are in the form "a.b.c". + * Nested type names are in the qualified form "A.M". + * The default package is represented by an empty array. + */ + public void acceptType(char[] packageName, char[] typeName) { + acceptClass(packageName, typeName, 0); + } + + private boolean checkSelection( + char[] source, + int selectionStart, + int selectionEnd) { + + Scanner scanner = new Scanner(); + scanner.setSource(source); + + int lastIdentifierStart = -1; + int lastIdentifierEnd = -1; + char[] lastIdentifier = null; + int token, identCount = 0; + StringBuffer entireSelection = new StringBuffer(selectionEnd - selectionStart + 1); + + if(selectionStart > selectionEnd){ + + // compute start position of current line + int currentPosition = selectionStart - 1; + int nextCharacterPosition = selectionStart; + char currentCharacter = ' '; + try { + while(currentPosition > 0 || currentCharacter == '\r' || currentCharacter == '\n'){ + + if(source[currentPosition] == '\\' && source[currentPosition+1] == 'u') { + int pos = currentPosition + 2; + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + while (source[pos] == 'u') { + pos++; + } + if ((c1 = Character.getNumericValue(source[pos++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[pos++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[pos++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[pos++])) > 15 + || c4 < 0) { + return false; + } else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + nextCharacterPosition = pos; + } + } else { + currentCharacter = source[currentPosition]; + nextCharacterPosition = currentPosition+1; + } + + if(currentCharacter == '\r' || currentCharacter == '\n') { + break; + } + currentPosition--; + } + } + catch (ArrayIndexOutOfBoundsException e) { + return false; + } + + // compute start and end of the last token + scanner.resetTo(nextCharacterPosition, selectionEnd); + do { + try { + token = scanner.getNextToken(); + } catch (InvalidInputException e) { + return false; + } + if(( + // token == ITerminalSymbols.TokenNamethis || + // token == ITerminalSymbols.TokenNamesuper || + token == ITerminalSymbols.TokenNameIdentifier) && + scanner.startPosition <= selectionStart && + selectionStart <= scanner.currentPosition) { + lastIdentifierStart = scanner.startPosition; + lastIdentifierEnd = scanner.currentPosition - 1; + lastIdentifier = scanner.getCurrentTokenSource(); + } + } while (token != ITerminalSymbols.TokenNameEOF); + } else { + scanner.resetTo(selectionStart, selectionEnd); + + boolean expectingIdentifier = true; + + do { + try { + token = scanner.getNextToken(); + } catch (InvalidInputException e) { + return false; + } + switch (token) { +// case ITerminalSymbols.TokenNamethis : +// case ITerminalSymbols.TokenNamesuper : + case ITerminalSymbols.TokenNameIdentifier : + if (!expectingIdentifier) + return false; + lastIdentifier = scanner.getCurrentTokenSource(); + lastIdentifierStart = scanner.startPosition; + lastIdentifierEnd = scanner.currentPosition - 1; + if(lastIdentifierEnd > selectionEnd) { + lastIdentifierEnd = selectionEnd; + lastIdentifier = CharOperation.subarray(lastIdentifier, 0,lastIdentifierEnd - lastIdentifierStart + 1); + } + entireSelection.append(lastIdentifier); + + identCount++; + expectingIdentifier = false; + break; + case ITerminalSymbols.TokenNameDOT : + if (expectingIdentifier) + return false; + entireSelection.append('.'); + expectingIdentifier = true; + break; + case ITerminalSymbols.TokenNameEOF : + if (expectingIdentifier) + return false; + break; + default : + return false; + } + } while (token != ITerminalSymbols.TokenNameEOF); + } + if (lastIdentifierStart > 0) { + actualSelectionStart = lastIdentifierStart; + actualSelectionEnd = lastIdentifierEnd; + selectedIdentifier = lastIdentifier; + if (identCount > 1) + qualifiedSelection = entireSelection.toString().toCharArray(); + return true; + } + return false; + } + + public AssistParser getParser() { + return parser; + } + + /** + * Ask the engine to compute the selection at the specified position + * of the given compilation unit. + + * @param sourceUnit net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit + * the source of the current compilation unit. + * + * @param selectionSourceStart int + * @param selectionSourceEnd int + * a range in the source where the selection is. + */ + public void select( + ICompilationUnit sourceUnit, + int selectionSourceStart, + int selectionSourceEnd) { + + char[] source = sourceUnit.getContents(); + + if(DEBUG) { + System.out.print("SELECTION IN "); //$NON-NLS-1$ + System.out.print(sourceUnit.getFileName()); + System.out.print(" FROM "); //$NON-NLS-1$ + System.out.print(selectionSourceStart); + System.out.print(" TO "); //$NON-NLS-1$ + System.out.println(selectionSourceEnd); + System.out.println("SELECTION - Source :"); //$NON-NLS-1$ + System.out.println(source); + } + if (!checkSelection(source, selectionSourceStart, selectionSourceEnd)) + return; + try { + acceptedAnswer = false; + CompilationResult result = new CompilationResult(sourceUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = + parser.dietParse(sourceUnit, result, actualSelectionStart, actualSelectionEnd); + + if (parsedUnit != null) { + if(DEBUG) { + System.out.println("SELECTION - Diet AST :"); //$NON-NLS-1$ + System.out.println(parsedUnit.toString()); + } + + // scan the package & import statements first + if (parsedUnit.currentPackage instanceof SelectionOnPackageReference) { + char[][] tokens = + ((SelectionOnPackageReference) parsedUnit.currentPackage).tokens; + requestor.acceptPackage(CharOperation.concatWith(tokens, '.')); + return; + } + ImportReference[] imports = parsedUnit.imports; + if (imports != null) { + for (int i = 0, length = imports.length; i < length; i++) { + ImportReference importReference = imports[i]; + if (importReference instanceof SelectionOnImportReference) { + char[][] tokens = ((SelectionOnImportReference) importReference).tokens; + requestor.acceptPackage(CharOperation.concatWith(tokens, '.')); + nameEnvironment.findTypes(CharOperation.concatWith(tokens, '.'), this); + // accept qualified types only if no unqualified type was accepted + if(!acceptedAnswer) { + acceptQualifiedTypes(); + if (!acceptedAnswer) { + nameEnvironment.findTypes(selectedIdentifier, this); + // try with simple type name + if(!acceptedAnswer) { + acceptQualifiedTypes(); + } + } + } + return; + } + } + } + if (parsedUnit.types != null) { + lookupEnvironment.buildTypeBindings(parsedUnit); + if ((this.unitScope = parsedUnit.scope) != null) { + try { + lookupEnvironment.completeTypeBindings(parsedUnit, true); + parsedUnit.scope.faultInTypes(); + selectDeclaration(parsedUnit); + parseMethod(parsedUnit, selectionSourceStart); + if(DEBUG) { + System.out.println("SELECTION - AST :"); //$NON-NLS-1$ + System.out.println(parsedUnit.toString()); + } + parsedUnit.resolve(); + } catch (SelectionNodeFound e) { + if (e.binding != null) { + if(DEBUG) { + System.out.println("SELECTION - Selection binding:"); //$NON-NLS-1$ + System.out.println(e.binding.toString()); + } + // if null then we found a problem in the selection node + selectFrom(e.binding); + } + } + } + } + } + // only reaches here if no selection could be derived from the parsed tree + // thus use the selected source and perform a textual type search + if (!acceptedAnswer) { + nameEnvironment.findTypes(selectedIdentifier, this); + + // accept qualified types only if no unqualified type was accepted + if(!acceptedAnswer) { + acceptQualifiedTypes(); + } + } + } catch (IndexOutOfBoundsException e) { // work-around internal failure - 1GEMF6D + } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object + } finally { + reset(); + } + } + + private void selectFrom(Binding binding) { + if (binding instanceof ReferenceBinding) { + ReferenceBinding typeBinding = (ReferenceBinding) binding; + if (qualifiedSelection != null + && !CharOperation.equals(qualifiedSelection, typeBinding.readableName())) { + return; + } + if (typeBinding.isInterface()) { + requestor.acceptInterface( + typeBinding.qualifiedPackageName(), + typeBinding.qualifiedSourceName(), + false); + } else if(typeBinding instanceof ProblemReferenceBinding){ + ProblemReferenceBinding problemBinding = (ProblemReferenceBinding)typeBinding; + if(problemBinding.original == null + || !(problemBinding.original instanceof ReferenceBinding)) { + return; + } + ReferenceBinding original = (ReferenceBinding) problemBinding.original; + + requestor.acceptClass( + original.qualifiedPackageName(), + original.qualifiedSourceName(), + false); + } else { + requestor.acceptClass( + typeBinding.qualifiedPackageName(), + typeBinding.qualifiedSourceName(), + false); + } + acceptedAnswer = true; + } else + if (binding instanceof MethodBinding) { + MethodBinding methodBinding = (MethodBinding) binding; + TypeBinding[] parameterTypes = methodBinding.parameters; + int length = parameterTypes.length; + char[][] parameterPackageNames = new char[length][]; + char[][] parameterTypeNames = new char[length][]; + for (int i = 0; i < length; i++) { + parameterPackageNames[i] = parameterTypes[i].qualifiedPackageName(); + parameterTypeNames[i] = parameterTypes[i].qualifiedSourceName(); + } + requestor.acceptMethod( + methodBinding.declaringClass.qualifiedPackageName(), + methodBinding.declaringClass.qualifiedSourceName(), + methodBinding.isConstructor() + ? methodBinding.declaringClass.sourceName() + : methodBinding.selector, + parameterPackageNames, + parameterTypeNames, + methodBinding.isConstructor()); + acceptedAnswer = true; + } else + if (binding instanceof FieldBinding) { + FieldBinding fieldBinding = (FieldBinding) binding; + if (fieldBinding.declaringClass != null) { // arraylength + requestor.acceptField( + fieldBinding.declaringClass.qualifiedPackageName(), + fieldBinding.declaringClass.qualifiedSourceName(), + fieldBinding.name); + acceptedAnswer = true; + } + } else + if (binding instanceof LocalVariableBinding) { + selectFrom(((LocalVariableBinding) binding).type); + // open on the type of the variable + } else + if (binding instanceof ArrayBinding) { + selectFrom(((ArrayBinding) binding).leafComponentType); + // open on the type of the array + } else + if (binding instanceof PackageBinding) { + PackageBinding packageBinding = (PackageBinding) binding; + requestor.acceptPackage(packageBinding.readableName()); + acceptedAnswer = true; + } else + if(binding instanceof BaseTypeBinding) { + acceptedAnswer = true; + } + } + + /** + * Asks the engine to compute the selection of the given type + * from the source type. + * + * @param sourceType net.sourceforge.phpdt.internal.compiler.env.ISourceType + * a source form of the current type in which code assist is invoked. + * + * @param typeName char[] + * a type name which is to be resolved in the context of a compilation unit. + * NOTE: the type name is supposed to be correctly reduced (no whitespaces, no unicodes left) + * + * @param searchInEnvironment + * if true and no selection could be found in context then search type in environment. + */ + public void selectType(ISourceType sourceType, char[] typeName, boolean searchInEnvironment) { + try { + acceptedAnswer = false; + + // find the outer most type + ISourceType outerType = sourceType; + ISourceType parent = sourceType.getEnclosingType(); + while (parent != null) { + outerType = parent; + parent = parent.getEnclosingType(); + } + // compute parse tree for this most outer type + CompilationResult result = new CompilationResult(outerType.getFileName(), 1, 1, this.compilerOptions.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = + SourceTypeConverter + .buildCompilationUnit( + new ISourceType[] { outerType }, + false, + // don't need field and methods + true, // by default get member types + this.parser.problemReporter(), result); + + if (parsedUnit != null && parsedUnit.types != null) { + if(DEBUG) { + System.out.println("SELECTION - Diet AST :"); //$NON-NLS-1$ + System.out.println(parsedUnit.toString()); + } + // find the type declaration that corresponds to the original source type + char[] packageName = sourceType.getPackageName(); + char[] sourceTypeName = sourceType.getQualifiedName(); + // the fully qualified name without the package name + if (packageName != null) { + // remove the package name if necessary + sourceTypeName = + CharOperation.subarray( + sourceType.getQualifiedName(), + packageName.length + 1, + sourceTypeName.length); + }; + TypeDeclaration typeDecl = + parsedUnit.declarationOfType(CharOperation.splitOn('.', sourceTypeName)); + if (typeDecl != null) { + + // add fake field with the type we're looking for + // note: since we didn't ask for fields above, there is no field defined yet + FieldDeclaration field = new FieldDeclaration(); + int dot; + if ((dot = CharOperation.lastIndexOf('.', typeName)) == -1) { + this.selectedIdentifier = typeName; + field.type = new SelectionOnSingleTypeReference(typeName, -1); + // position not used + } else { + qualifiedSelection = typeName; + char[][] previousIdentifiers = CharOperation.splitOn('.', typeName, 0, dot - 1); + char[] selectionIdentifier = + CharOperation.subarray(typeName, dot + 1, typeName.length); + this.selectedIdentifier = selectionIdentifier; + field.type = + new SelectionOnQualifiedTypeReference( + previousIdentifiers, + selectionIdentifier, + new long[previousIdentifiers.length + 1]); + } + field.name = "".toCharArray(); //$NON-NLS-1$ + typeDecl.fields = new FieldDeclaration[] { field }; + + // build bindings + lookupEnvironment.buildTypeBindings(parsedUnit); + if ((this.unitScope = parsedUnit.scope) != null) { + try { + // build fields + // note: this builds fields only in the parsed unit (the buildFieldsAndMethods flag is not passed along) + this.lookupEnvironment.completeTypeBindings(parsedUnit, true); + + // resolve + parsedUnit.scope.faultInTypes(); + parsedUnit.resolve(); + } catch (SelectionNodeFound e) { + if (e.binding != null) { + if(DEBUG) { + System.out.println("SELECTION - Selection binding :"); //$NON-NLS-1$ + System.out.println(e.binding.toString()); + } + // if null then we found a problem in the selection node + selectFrom(e.binding); + } + } + } + } + } + // only reaches here if no selection could be derived from the parsed tree + // thus use the selected source and perform a textual type search + if (!acceptedAnswer && searchInEnvironment) { + if (this.selectedIdentifier != null) { + nameEnvironment.findTypes(typeName, this); + + // accept qualified types only if no unqualified type was accepted + if(!acceptedAnswer) { + acceptQualifiedTypes(); + } + } + } + } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object + } finally { + qualifiedSelection = null; + reset(); + } + } + + // Check if a declaration got selected in this unit + private void selectDeclaration(CompilationUnitDeclaration compilationUnit){ + + // the selected identifier is not identical to the parser one (equals but not identical), + // for traversing the parse tree, the parser assist identifier is necessary for identitiy checks + char[] assistIdentifier = this.getParser().assistIdentifier(); + if (assistIdentifier == null) return; + + // iterate over the types + TypeDeclaration[] types = compilationUnit.types; + for (int i = 0, length = types == null ? 0 : types.length; i < length; i++){ + selectDeclaration(types[i], assistIdentifier); + } + } + + // Check if a declaration got selected in this type + private void selectDeclaration(TypeDeclaration typeDeclaration, char[] assistIdentifier){ + + if (typeDeclaration.name == assistIdentifier){ + throw new SelectionNodeFound(typeDeclaration.binding); + } + TypeDeclaration[] memberTypes = typeDeclaration.memberTypes; + for (int i = 0, length = memberTypes == null ? 0 : memberTypes.length; i < length; i++){ + selectDeclaration(memberTypes[i], assistIdentifier); + } + FieldDeclaration[] fields = typeDeclaration.fields; + for (int i = 0, length = fields == null ? 0 : fields.length; i < length; i++){ + if (fields[i].name == assistIdentifier){ + throw new SelectionNodeFound(fields[i].binding); + } + } + AbstractMethodDeclaration[] methods = typeDeclaration.methods; + for (int i = 0, length = methods == null ? 0 : methods.length; i < length; i++){ + AbstractMethodDeclaration method = methods[i]; + if (method.selector == assistIdentifier){ + if(method.binding != null) { + throw new SelectionNodeFound(method.binding); + } else { + if(method.scope != null) { + throw new SelectionNodeFound(new MethodBinding(method.modifiers, method.selector, null, null, null, method.scope.referenceType().binding)); + } + } + } + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionNodeFound.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionNodeFound.java new file mode 100644 index 0000000..41e45e5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionNodeFound.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.lookup.Binding; +import net.sourceforge.phpdt.internal.compiler.lookup.Scope; + +public class CompletionNodeFound extends RuntimeException { + public AstNode astNode; + public Binding qualifiedBinding; + public Scope scope; +public CompletionNodeFound() { + this(null, null, null); // we found a problem in the completion node +} +public CompletionNodeFound(AstNode astNode, Binding qualifiedBinding, Scope scope) { + this.astNode = astNode; + this.qualifiedBinding = qualifiedBinding; + this.scope = scope; +} +public CompletionNodeFound(AstNode astNode, Scope scope) { + this(astNode, null, scope); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnArgumentName.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnArgumentName.java new file mode 100644 index 0000000..50bb859 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnArgumentName.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +import net.sourceforge.phpdt.internal.compiler.ast.Argument; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + + +public class CompletionOnArgumentName extends Argument { + private static final char[] FAKENAMESUFFIX = " ".toCharArray(); //$NON-NLS-1$ + public char[] realName; + public CompletionOnArgumentName(char[] name , long posNom , TypeReference tr , int modifiers){ + super(CharOperation.concat(name, FAKENAMESUFFIX), posNom, tr, modifiers); + this.realName = name; + } + + public void resolve(BlockScope scope) { + super.resolve(scope); + throw new CompletionNodeFound(this, scope); + } + + public void bind(MethodScope scope, TypeBinding typeBinding, boolean used) { + super.bind(scope, typeBinding, used); + + throw new CompletionNodeFound(this, scope); + } + + public String toString(int tab) { + String s = tabString(tab); + s += " class X { + * void foo() { + * + * } + * } + * + * The source range of the completion node denotes the source range + * which should be replaced by the completion. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnClassLiteralAccess extends ClassLiteralAccess { + public char[] completionIdentifier; + public int classStart; + +public CompletionOnClassLiteralAccess(long pos, TypeReference t) { + super((int)pos, t); + this.classStart = (int) (pos >>> 32); +} +public TypeBinding resolveType(BlockScope scope) { + if (super.resolveType(scope) == null) + throw new CompletionNodeFound(); + else + throw new CompletionNodeFound(this, targetType, scope); +} +public String toStringExpression() { + StringBuffer result = new StringBuffer(""); //$NON-NLS-1$ + return result.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnClassReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnClassReference.java new file mode 100644 index 0000000..f22f53c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnClassReference.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +public class CompletionOnClassReference extends CompletionOnSingleTypeReference { + public CompletionOnClassReference(char[] source, long pos) { + super(source, pos); + } + public String toStringExpression(int tab) { + return ""; //$NON-NLS-2$ //$NON-NLS-1$ + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnExceptionReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnExceptionReference.java new file mode 100644 index 0000000..f3f723e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnExceptionReference.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce an exception type reference containing the completion identifier. + * e.g. + * + * class X { + * void foo() { + * try { + * bar(); + * } catch (IOExc[cursor] e) { + * } + * } + * } + * + * ---> class X { + * void foo() { + * try { + * bar(); + * } catch ( e) { + * } + * } + * } + * + * The source range of the completion node denotes the source range + * which should be replaced by the completion. + */ +public class CompletionOnExceptionReference extends CompletionOnSingleTypeReference { +public CompletionOnExceptionReference(char[] source, long pos) { + super(source, pos); +} +public String toStringExpression(int tab) { + return ""; //$NON-NLS-2$ //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnExplicitConstructorCall.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnExplicitConstructorCall.java new file mode 100644 index 0000000..50d998e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnExplicitConstructorCall.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce a explicit constructor call containing the cursor. + * e.g. + * + * class X { + * X() { + * this(1, 2, [cursor] + * } + * } + * + * ---> class X { + * X() { + * + * } + * } + * + * The source range is always of length 0. + * The arguments of the constructor call are all the arguments defined + * before the cursor. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnExplicitConstructorCall extends ExplicitConstructorCall { +public CompletionOnExplicitConstructorCall(int accessMode) { + super(accessMode); +} +public void resolve(BlockScope scope) { + ReferenceBinding receiverType = scope.enclosingSourceType(); + + if (accessMode != This && receiverType != null) { + if (receiverType.isHierarchyInconsistent()) + throw new CompletionNodeFound(); + receiverType = receiverType.superclass(); + } + if (receiverType == null) + throw new CompletionNodeFound(); + else + throw new CompletionNodeFound(this, receiverType, scope); +} +public String toString(int tab) { + String s = tabString(tab); + s += " class X { + * ; + * } + * + * The source range is always of length 0. + * The arguments of the allocation expression are all the arguments defined + * before the cursor. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnFieldType extends FieldDeclaration { + public boolean isLocalVariable; + +public CompletionOnFieldType(TypeReference type, boolean isLocalVariable){ + super(); + this.sourceStart = type.sourceStart; + this.sourceEnd = type.sourceEnd; + this.type = type; + this.name = NoChar; + this.isLocalVariable = isLocalVariable; +} +public TypeBinding getTypeBinding(Scope scope) { + if(type instanceof CompletionOnSingleTypeReference) + throw new CompletionNodeFound(this, scope); + else // handle the qualified type ref directly + return type.getTypeBinding(scope); +} +public String toString(int tab) { + + return type.toString(tab); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnImportReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnImportReference.java new file mode 100644 index 0000000..8aff63e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnImportReference.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce an import reference containing the cursor location. + * e.g. + * + * import java.io[cursor]; + * class X { + * void foo() { + * } + * } + * + * ---> + * class X { + * void foo() { + * } + * } + * + * The source range is always of length 0. + * The arguments of the allocation expression are all the arguments defined + * before the cursor. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; + +public class CompletionOnImportReference extends ImportReference { + +public CompletionOnImportReference(char[][] tokens , long[] positions) { + super(tokens, positions, false); +} +public String toString(int tab, boolean withOnDemand) { + + StringBuffer buffer = new StringBuffer(tabString(tab)); + buffer. append(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnInterfaceReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnInterfaceReference.java new file mode 100644 index 0000000..a52fdf7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnInterfaceReference.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +public class CompletionOnInterfaceReference extends CompletionOnSingleTypeReference { + public CompletionOnInterfaceReference(char[] source, long pos) { + super(source, pos); + } + public String toStringExpression(int tab) { + return ""; //$NON-NLS-2$ //$NON-NLS-1$ + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnLocalName.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnLocalName.java new file mode 100644 index 0000000..8d4feb5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnLocalName.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +import net.sourceforge.phpdt.internal.compiler.ast.Expression; +import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + + +public class CompletionOnLocalName extends LocalDeclaration { + private static final char[] FAKENAMESUFFIX = " ".toCharArray(); //$NON-NLS-1$ + public char[] realName; + public CompletionOnLocalName(Expression expr,char[] name, int sourceStart, int sourceEnd){ + super(expr, CharOperation.concat(name, FAKENAMESUFFIX), sourceStart, sourceEnd); + this.realName = name; + } + + public void resolve(BlockScope scope) { + super.resolve(scope); + + throw new CompletionNodeFound(this, scope); + } + public String toString(int tab) { + String s = tabString(tab); + s += " class X { + * void foo() { + * + * } + * } + * + * The source range of the completion node denotes the source range + * which should be replaced by the completion. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnMemberAccess extends FieldReference { + + public CompletionOnMemberAccess(char[] source, long pos) { + super(source, pos); + } + + public TypeBinding resolveType(BlockScope scope) { + TypeBinding receiverType = receiver.resolveType(scope); + if (receiverType == null || receiverType.isBaseType()) + throw new CompletionNodeFound(); + else + throw new CompletionNodeFound(this, receiverType, scope); + // array types are passed along to find the length field + } + + public String toStringExpression() { + + return ""; //$NON-NLS-1$ + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMessageSend.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMessageSend.java new file mode 100644 index 0000000..0882c74 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMessageSend.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce a message send containing the cursor. + * e.g. + * + * class X { + * void foo() { + * this.bar(1, 2, [cursor] + * } + * } + * + * ---> class X { + * void foo() { + * + * } + * } + * + * The source range is always of length 0. + * The arguments of the message send are all the arguments defined + * before the cursor. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnMessageSend extends MessageSend { + + public TypeBinding resolveType(BlockScope scope) { + if (receiver == ThisReference.ThisImplicit) + throw new CompletionNodeFound(this, null, scope); + + TypeBinding receiverType = receiver.resolveType(scope); + if (receiverType == null || receiverType.isBaseType()) + throw new CompletionNodeFound(); + + if (receiverType.isArrayType()) + receiverType = scope.getJavaLangObject(); + throw new CompletionNodeFound(this, receiverType, scope); + } + + public String toStringExpression() { + + String s = ""; //$NON-NLS-1$ + return s; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMethodName.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMethodName.java new file mode 100644 index 0000000..9679be1 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMethodName.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope; + +public class CompletionOnMethodName extends MethodDeclaration { + public int selectorEnd; + + public CompletionOnMethodName(CompilationResult compilationResult){ + super(compilationResult); + } + + public void resolve(ClassScope upperScope) { + + super.resolve(upperScope); + throw new CompletionNodeFound(this, upperScope); + } + + public String toString(int tab) { + + String s = tabString(tab); + s += " + * class X { + * void foo() { + * } + * } + * + * The source range is always of length 0. + * The arguments of the allocation expression are all the arguments defined + * before the cursor. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; + +public class CompletionOnPackageReference extends ImportReference { +public CompletionOnPackageReference(char[][] tokens , long[] positions) { + super(tokens, positions, true); +} +public String toString(int tab, boolean withOnDemand) { + StringBuffer buffer = new StringBuffer(tabString(tab)); + buffer. append(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedAllocationExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedAllocationExpression.java new file mode 100644 index 0000000..6aec572 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedAllocationExpression.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce an allocation expression containing the cursor. + * If the allocation expression is not qualified, the enclosingInstance field + * is null. + * e.g. + * + * class X { + * void foo() { + * new Bar(1, 2, [cursor] + * } + * } + * + * ---> class X { + * void foo() { + * + * } + * } + * + * The source range is always of length 0. + * The arguments of the allocation expression are all the arguments defined + * before the cursor. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnQualifiedAllocationExpression extends QualifiedAllocationExpression { +public TypeBinding resolveType(BlockScope scope) { + TypeBinding typeBinding = null; + if (enclosingInstance != null) { + TypeBinding enclosingType = enclosingInstance.resolveType(scope); + if (!(enclosingType instanceof ReferenceBinding)) { + scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance(enclosingType, enclosingInstance); + throw new CompletionNodeFound(); + } + typeBinding = ((SingleTypeReference) type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingType); + if (!(typeBinding instanceof ReferenceBinding)) + throw new CompletionNodeFound(); // no need to continue if its an array or base type + if (typeBinding.isInterface()) // handle the anonymous class definition case + typeBinding = scope.getJavaLangObject(); + } else { + typeBinding = type.resolveType(scope); + if (!(typeBinding instanceof ReferenceBinding)) + throw new CompletionNodeFound(); // no need to continue if its an array or base type + } + + throw new CompletionNodeFound(this, typeBinding, scope); +} +public String toStringExpression(int tab) { + return + ((this.enclosingInstance == null) ? + ""; //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedClassReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedClassReference.java new file mode 100644 index 0000000..7d28391 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedClassReference.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +public class CompletionOnQualifiedClassReference extends CompletionOnQualifiedTypeReference { +public CompletionOnQualifiedClassReference(char[][] previousIdentifiers, char[] completionIdentifier, long[] positions) { + super(previousIdentifiers, completionIdentifier, positions); +} +public String toStringExpression(int tab) { + + StringBuffer buffer = new StringBuffer(); + buffer. append(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedExceptionReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedExceptionReference.java new file mode 100644 index 0000000..f788b6e --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedExceptionReference.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce an exception type reference containing the completion identifier + * as part of a qualified name. + * e.g. + * + * class X { + * void foo() { + * try { + * bar(); + * } catch (java.io.IOExc[cursor] e) { + * } + * } + * } + * + * ---> class X { + * void foo() { + * try { + * bar(); + * } catch ( e) { + * } + * } + * } + * + * The source range of the completion node denotes the source range + * which should be replaced by the completion. + */ +public class CompletionOnQualifiedExceptionReference extends CompletionOnQualifiedTypeReference { +public CompletionOnQualifiedExceptionReference(char[][] previousIdentifiers, char[] completionIdentifier, long[] positions) { + super(previousIdentifiers, completionIdentifier, positions); +} +public String toStringExpression(int tab) { + + StringBuffer buffer = new StringBuffer(); + buffer. append(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedInterfaceReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedInterfaceReference.java new file mode 100644 index 0000000..aca5446 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedInterfaceReference.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +public class CompletionOnQualifiedInterfaceReference extends CompletionOnQualifiedTypeReference { +public CompletionOnQualifiedInterfaceReference(char[][] previousIdentifiers, char[] completionIdentifier, long[] positions) { + super(previousIdentifiers, completionIdentifier, positions); +} +public String toStringExpression(int tab) { + + StringBuffer buffer = new StringBuffer(); + buffer. append(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java new file mode 100644 index 0000000..ad0cda8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce a qualified name reference containing the completion identifier. + * e.g. + * + * class X { + * Y y; + * void foo() { + * y.fred.ba[cursor] + * } + * } + * + * ---> class X { + * Y y; + * void foo() { + * + * } + * } + * + * The source range of the completion node denotes the source range + * which should be replaced by the completion. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnQualifiedNameReference extends QualifiedNameReference { + public char[] completionIdentifier; + public long[] sourcePositions; // positions of each token, the last one being the positions of the completion identifier +public CompletionOnQualifiedNameReference(char[][] previousIdentifiers, char[] completionIdentifier, long[] positions) { + super(previousIdentifiers, (int) (positions[0] >>> 32), (int) positions[positions.length - 1]); + this.completionIdentifier = completionIdentifier; + this.sourcePositions = positions; +} +public CompletionOnQualifiedNameReference(char[][] previousIdentifiers, char[] completionIdentifier, int sourceStart, int sourceEnd) { + super(previousIdentifiers, sourceStart, sourceEnd); + this.completionIdentifier = completionIdentifier; + this.sourcePositions = new long[] {((long)sourceStart << 32) + sourceEnd}; +} +public TypeBinding resolveType(BlockScope scope) { + // it can be a package, type, member type, local variable or field + binding = scope.getBinding(tokens, this); + if (!binding.isValidBinding()) { + if (binding instanceof ProblemFieldBinding) { + scope.problemReporter().invalidField(this, (FieldBinding) binding); + } else if (binding instanceof ProblemReferenceBinding) { + scope.problemReporter().invalidType(this, (TypeBinding) binding); + } else { + scope.problemReporter().unresolvableReference(this, binding); + } + throw new CompletionNodeFound(); + } + + throw new CompletionNodeFound(this, binding, scope); +} +public String toStringExpression() { + + StringBuffer buffer = new StringBuffer(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java new file mode 100644 index 0000000..a62d389 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce a type reference containing the completion identifier as part + * of a qualified name. + * e.g. + * + * class X extends java.lang.Obj[cursor] + * + * ---> class X extends + * + * The source range of the completion node denotes the source range + * which should be replaced by the completion. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnQualifiedTypeReference extends QualifiedTypeReference { + public char[] completionIdentifier; +public CompletionOnQualifiedTypeReference(char[][] previousIdentifiers, char[] completionIdentifier, long[] positions) { + super(previousIdentifiers, positions); + this.completionIdentifier = completionIdentifier; +} +public void aboutToResolve(Scope scope) { + getTypeBinding(scope); +} +/* + * No expansion of the completion reference into an array one + */ +public TypeReference copyDims(int dim){ + return this; +} +public TypeBinding getTypeBinding(Scope scope) { + // it can be a package, type or member type + Binding binding = scope.parent.getTypeOrPackage(tokens); // step up from the ClassScope + if (!binding.isValidBinding()) { + scope.problemReporter().invalidType(this, (TypeBinding) binding); + throw new CompletionNodeFound(); + } + + throw new CompletionNodeFound(this, binding, scope); +} +public String toStringExpression(int tab) { + + StringBuffer buffer = new StringBuffer(); + buffer.append(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnSingleNameReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnSingleNameReference.java new file mode 100644 index 0000000..ed517e9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnSingleNameReference.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce a single name reference containing the completion identifier. + * e.g. + * + * class X { + * void foo() { + * ba[cursor] + * } + * } + * + * ---> class X { + * void foo() { + * + * } + * } + * + * The source range of the completion node denotes the source range + * which should be replaced by the completion. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnSingleNameReference extends SingleNameReference { +public CompletionOnSingleNameReference(char[] source, long pos) { + super(source, pos); +} +public TypeBinding resolveType(BlockScope scope) { + throw new CompletionNodeFound(this, scope); +} +public String toStringExpression() { + return ""; //$NON-NLS-2$ //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java new file mode 100644 index 0000000..a72d1f5 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Completion node build by the parser in any case it was intending to + * reduce a type reference containing the completion identifier as a single + * name reference. + * e.g. + * + * class X extends Obj[cursor] + * + * ---> class X extends + * + * The source range of the completion node denotes the source range + * which should be replaced by the completion. + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class CompletionOnSingleTypeReference extends SingleTypeReference { +public boolean isCompletionNode; +public CompletionOnSingleTypeReference(char[] source, long pos) { + super(source, pos); + isCompletionNode = true; +} +public void aboutToResolve(Scope scope) { + getTypeBinding(scope); +} +/* + * No expansion of the completion reference into an array one + */ +public TypeReference copyDims(int dim){ + return this; +} +public TypeBinding getTypeBinding(Scope scope) { + if(isCompletionNode) { + throw new CompletionNodeFound(this, scope); + } else { + return super.getTypeBinding(scope); + } +} +public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) { + if(isCompletionNode) { + throw new CompletionNodeFound(this, enclosingType, scope); + } else { + return super.resolveTypeEnclosing(scope, enclosingType); + } +} +public String toStringExpression(int tab){ + + return "" ; //$NON-NLS-2$ //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionParser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionParser.java new file mode 100644 index 0000000..228c98c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionParser.java @@ -0,0 +1,1386 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Parser able to build specific completion parse nodes, given a cursorLocation. + * + * Cursor location denotes the position of the last character behind which completion + * got requested: + * -1 means completion at the very beginning of the source + * 0 means completion behind the first character + * n means completion behind the n-th character + */ +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.env.*; + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.codeassist.impl.*; + +public class CompletionParser extends AssistParser { + + /* public fields */ + + public int cursorLocation; + public char[][] labels; // the visible labels up to the cursor location + public AstNode assistNodeParent; // the parent node of assist node + /* the following fields are internal flags */ + + boolean betweenNewAndLeftBraket; // whether we are between the keyword 'new' and the following left braket, ie. '[', '(' or '{' + boolean betweenCatchAndRightParen; // whether we are between the keyword 'catch' and the following ')' + boolean completionBehindDot; // true when completion identifier immediately follows a dot + + boolean nextTypeReferenceIsClass; + boolean nextTypeReferenceIsException; + boolean nextTypeReferenceIsInterface; + + int bracketDepth; + int throwBracketDepth; + + // the stacks of types and qualifiers for invocations (ie. method invocations, allocation expressions and + // explicit constructor invocations). They use the same stack pointer as the selector stack (ie. invocationPtr) + // the invocation type stack contains one of the invocation type constants below + // the qualifier stack contains pointers to the expression stack or -1 if there is no qualifier + // (a qualifier is the expression that qualifies a 'new', a 'super' constructor or a 'this' constructor + // or it is the receiver of a message send) + int[] invocationTypeStack = new int[StackIncrement]; + int[] qualifierStack = new int[StackIncrement]; + + // invocation type constants + static final int EXPLICIT_RECEIVER = 0; + static final int NO_RECEIVER = -1; + static final int SUPER_RECEIVER = -2; + static final int NAME_RECEIVER = -3; + static final int ALLOCATION = -4; + static final int QUALIFIED_ALLOCATION = -5; + + // the type of the current invocation (one of the invocation type constants) + int invocationType; + + // a pointer in the expression stack to the qualifier of a invocation + int qualifier; + + // a stack of label counters + // a new counter is pushed on the stack each time when a method (or a constructor) is entered, + // it is poped when the method (or constructor) is exited, + // it is incremented when a new label is defined + int labelCounterPtr; + int[] labelCounterStack = new int[StackIncrement]; + + // a stack of invocationPtr: contains the first invocationPtr of a block + // the current invocationPtr+1 is pushed when a block is entered + // it is poped when a block is exited + int blockInvocationPtr; + int[] blockInvocationStack = new int[StackIncrement]; + + // last modifiers info + int lastModifiers = AccDefault; + int lastModifiersStart = -1; + +public CompletionParser(ProblemReporter problemReporter, boolean assertMode) { + super(problemReporter, assertMode); +} +public char[] assistIdentifier(){ + return ((CompletionScanner)scanner).completionIdentifier; +} +protected void attachOrphanCompletionNode(){ + if (this.isOrphanCompletionNode) { + AstNode orphan = this.assistNode; + this.isOrphanCompletionNode = false; + + /* if in context of a type, then persists the identifier into a fake field return type */ + if (currentElement instanceof RecoveredType){ + RecoveredType recoveredType = (RecoveredType)currentElement; + /* filter out cases where scanner is still inside type header */ + if (recoveredType.foundOpeningBrace) { + /* generate a pseudo field with a completion on type reference */ + if (orphan instanceof TypeReference){ + CompletionOnFieldType fieldDeclaration = new CompletionOnFieldType((TypeReference)orphan, false); + + // retrieve available modifiers if any + if (intPtr >= 2 && intStack[intPtr-1] == this.lastModifiersStart && intStack[intPtr-2] == this.lastModifiers){ + fieldDeclaration.modifiersSourceStart = intStack[intPtr-1]; + fieldDeclaration.modifiers = intStack[intPtr-2]; + } + + currentElement = currentElement.add(fieldDeclaration, 0); + return; + } + } + } + /* if in context of a method, persists if inside arguments as a type */ + if (currentElement instanceof RecoveredMethod){ + RecoveredMethod recoveredMethod = (RecoveredMethod)currentElement; + /* only consider if inside method header */ + if (!recoveredMethod.foundOpeningBrace) { + //if (rParenPos < lParenPos){ // inside arguments + if (orphan instanceof TypeReference){ + currentElement = currentElement.parent.add( + new CompletionOnFieldType((TypeReference)orphan, true), 0); + return; + } + } + } + + // add the completion node to the method declaration or constructor declaration + if (orphan instanceof Statement) { + /* check for completion at the beginning of method body + behind an invalid signature + */ + RecoveredMethod method = currentElement.enclosingMethod(); + if (method != null){ + AbstractMethodDeclaration methodDecl = method.methodDeclaration; + if ((methodDecl.bodyStart == methodDecl.sourceEnd+1) // was missing opening brace + && (scanner.getLineNumber(orphan.sourceStart) == scanner.getLineNumber(methodDecl.sourceEnd))){ + return; + } + } + // add the completion node as a statement to the list of block statements + currentElement = currentElement.add((Statement)orphan, 0); + return; + } + } + + // the following code applies only in methods, constructors or initializers + if ((!this.inMethodStack[this.inMethodPtr] && !this.inFieldInitializationStack[this.inFieldInitializationPtr])) { + return; + } + + // push top expression on ast stack if it contains the completion node + Expression expression; + if (this.expressionPtr > -1 && containsCompletionNode(expression = this.expressionStack[this.expressionPtr])) { + /* check for completion at the beginning of method body + behind an invalid signature + */ + RecoveredMethod method = currentElement.enclosingMethod(); + if (method != null){ + AbstractMethodDeclaration methodDecl = method.methodDeclaration; + if ((methodDecl.bodyStart == methodDecl.sourceEnd+1) // was missing opening brace + && (scanner.getLineNumber(expression.sourceStart) == scanner.getLineNumber(methodDecl.sourceEnd))){ + return; + } + } + if (expression instanceof AllocationExpression) { + // keep the context if it is an allocation expression + Statement statement = (Statement)wrapWithExplicitConstructorCallIfNeeded(expression); + currentElement = currentElement.add(statement, 0); + } else { + Statement statement = (Statement)wrapWithExplicitConstructorCallIfNeeded(this.assistNode); + currentElement = currentElement.add(statement, 0); + } + } +} +public int bodyEnd(AbstractMethodDeclaration method){ + return cursorLocation; +} +public int bodyEnd(Initializer initializer){ + return cursorLocation; +} +/** + * Checks if the completion is on the exception type of a catch clause. + * Returns whether we found a completion node. + */ +private boolean checkCatchClause() { + if (this.betweenCatchAndRightParen && this.identifierPtr > -1) { + // NB: if the cursor is on the variable, then it has been reduced (so identifierPtr is -1), + // thus this can only be a completion on the type of the catch clause + this.assistNode = getTypeReference(0); + this.lastCheckPoint = this.assistNode.sourceEnd + 1; + this.isOrphanCompletionNode = true; + return true; + } + return false; +} +/** + * Checks if the completion is on the type following a 'new'. + * Returns whether we found a completion node. + */ +private boolean checkClassInstanceCreation() { + if (this.betweenNewAndLeftBraket) { + // completion on type inside an allocation expression + + if(this.throwBracketDepth != -1 && this.throwBracketDepth == this.bracketDepth) { + this.nextTypeReferenceIsException = true; + } + TypeReference type = getTypeReference(0); + this.nextTypeReferenceIsException = false; + this.assistNode = type; + this.lastCheckPoint = type.sourceEnd + 1; + if (this.invocationType == ALLOCATION) { + // non qualified allocation expression + AllocationExpression allocExpr = new AllocationExpression(); + allocExpr.type = type; + allocExpr.sourceStart = type.sourceStart; + allocExpr.sourceEnd = type.sourceEnd; + pushOnExpressionStack(allocExpr); + this.isOrphanCompletionNode = false; + } else { + // qualified allocation expression + QualifiedAllocationExpression allocExpr = new QualifiedAllocationExpression(); + allocExpr.type = type; + allocExpr.enclosingInstance = this.expressionStack[this.qualifier]; + allocExpr.sourceStart = this.intStack[this.intPtr--]; + allocExpr.sourceEnd = type.sourceEnd; + this.expressionStack[this.qualifier] = allocExpr; // attach it now (it replaces the qualifier expression) + this.isOrphanCompletionNode = false; + } + return true; + } + return false; +} +/** + * Checks if the completion is on the dot following an array type, + * a primitive type or an primitive array type. + * Returns whether we found a completion node. + */ +private boolean checkClassLiteralAccess() { + if (this.identifierLengthPtr >= 1 && this.previousToken == TokenNameDOT) { // (NB: the top id length is 1 and it is for the completion identifier) + int length; + // if the penultimate id length is negative, + // the completion is after a primitive type or a primitive array type + if ((length = this.identifierLengthStack[this.identifierLengthPtr-1]) < 0) { + // build the primitive type node + int dim = this.isAfterArrayType() ? this.intStack[this.intPtr--] : 0; + SingleTypeReference typeRef = (SingleTypeReference)TypeReference.baseTypeReference(-length, dim); + typeRef.sourceStart = this.intStack[this.intPtr--]; + if (dim == 0) { + typeRef.sourceEnd = this.intStack[this.intPtr--]; + } else { + this.intPtr--; + typeRef.sourceEnd = this.endPosition; + } + //typeRef.sourceEnd = typeRef.sourceStart + typeRef.token.length; // NB: It's ok to use the length of the token since it doesn't contain any unicode + + // find the completion identifier and its source positions + char[] source = identifierStack[identifierPtr]; + long pos = this.identifierPositionStack[this.identifierPtr--]; + this.identifierLengthPtr--; // it can only be a simple identifier (so its length is one) + + // build the completion on class literal access node + CompletionOnClassLiteralAccess access = new CompletionOnClassLiteralAccess(pos, typeRef); + access.completionIdentifier = source; + this.identifierLengthPtr--; // pop the length that was used to say it is a primitive type + this.assistNode = access; + this.isOrphanCompletionNode = true; + return true; + } + + // if the completion is after a regular array type + if (isAfterArrayType()) { + // find the completion identifier and its source positions + char[] source = identifierStack[identifierPtr]; + long pos = this.identifierPositionStack[this.identifierPtr--]; + this.identifierLengthPtr--; // it can only be a simple identifier (so its length is one) + + // get the type reference + TypeReference typeRef = getTypeReference(this.intPtr--); + + // build the completion on class literal access node + CompletionOnClassLiteralAccess access = new CompletionOnClassLiteralAccess(pos, typeRef); + access.completionIdentifier = source; + this.assistNode = access; + this.isOrphanCompletionNode = true; + return true; + } + + } + return false; +} +/** + * Checks if the completion is inside a method invocation or a constructor invocation. + * Returns whether we found a completion node. + */ +private boolean checkInvocation() { + Expression topExpression = this.expressionPtr >= 0 ? + this.expressionStack[this.expressionPtr] : + null; + boolean isEmptyNameCompletion = false; + boolean isEmptyAssistIdentifier = false; + int startInvocationPtr = this.blockInvocationPtr >= 0 ? this.blockInvocationStack[this.blockInvocationPtr] : 0; + if (this.invocationPtr >= startInvocationPtr + && ((isEmptyNameCompletion = topExpression == this.assistNode && this.isEmptyNameCompletion()) // eg. it is something like "this.fred([cursor]" but it is not something like "this.fred(1 + [cursor]" + || (isEmptyAssistIdentifier = this.indexOfAssistIdentifier() >= 0 && this.identifierStack[this.identifierPtr].length == 0))) { // eg. it is something like "this.fred(1 [cursor]" + + // pop empty name completion + if (isEmptyNameCompletion) { + this.expressionPtr--; + this.expressionLengthStack[this.expressionLengthPtr]--; + } else if (isEmptyAssistIdentifier) { + this.identifierPtr--; + this.identifierLengthPtr--; + } + + // find receiver and qualifier + int invocationType = this.invocationTypeStack[this.invocationPtr]; + int qualifierExprPtr = this.qualifierStack[this.invocationPtr]; + + // find arguments + int numArgs = this.expressionPtr - qualifierExprPtr; + int argStart = qualifierExprPtr + 1; + Expression[] arguments = null; + if (numArgs > 0) { + // remember the arguments + arguments = new Expression[numArgs]; + System.arraycopy(this.expressionStack, argStart, arguments, 0, numArgs); + + // consume the expression arguments + this.expressionPtr -= numArgs; + int count = numArgs; + while (count > 0) { + count -= this.expressionLengthStack[this.expressionLengthPtr--]; + } + } + + // build ast node + if (invocationType != ALLOCATION && invocationType != QUALIFIED_ALLOCATION) { + // creates completion on message send + CompletionOnMessageSend messageSend = new CompletionOnMessageSend(); + messageSend.arguments = arguments; + switch (invocationType) { + case NO_RECEIVER: + // implicit this + messageSend.receiver = ThisReference.ThisImplicit; + break; + case NAME_RECEIVER: + // remove special flags for primitive types + while (this.identifierLengthPtr >= 0 && this.identifierLengthStack[this.identifierLengthPtr] < 0) { + this.identifierLengthPtr--; + } + + // remove selector + this.identifierPtr--; + this.identifierLengthStack[this.identifierLengthPtr]--; + // consume the receiver + messageSend.receiver = this.getUnspecifiedReference(); + break; + case SUPER_RECEIVER: + messageSend.receiver = SuperReference.Super; + break; + case EXPLICIT_RECEIVER: + messageSend.receiver = this.expressionStack[qualifierExprPtr]; + } + + // set selector + int selectorPtr = this.selectorStack[this.invocationPtr]; + messageSend.selector = this.identifierStack[selectorPtr]; + // remove selector + if (this.identifierLengthPtr >=0 && this.identifierLengthStack[this.identifierLengthPtr] == 1) { + this.identifierPtr--; + this.identifierLengthPtr--; + } + + // the entire message may be replaced in case qualification is needed + messageSend.sourceStart = (int)(this.identifierPositionStack[selectorPtr] >> 32); //this.cursorLocation + 1; + messageSend.sourceEnd = this.cursorLocation; + + // remember the message send as an orphan completion node + this.assistNode = messageSend; + this.lastCheckPoint = messageSend.sourceEnd + 1; + this.isOrphanCompletionNode = true; + return true; + } else { + int selectorPtr = this.selectorStack[this.invocationPtr]; + if (selectorPtr == THIS_CONSTRUCTOR || selectorPtr == SUPER_CONSTRUCTOR) { + // creates an explicit constructor call + CompletionOnExplicitConstructorCall call = new CompletionOnExplicitConstructorCall( + (selectorPtr == THIS_CONSTRUCTOR) ? ExplicitConstructorCall.This : ExplicitConstructorCall.Super); + call.arguments = arguments; + if (invocationType == QUALIFIED_ALLOCATION) { + call.qualification = this.expressionStack[qualifierExprPtr]; + } + + // no source is going to be replaced + call.sourceStart = this.cursorLocation + 1; + call.sourceEnd = this.cursorLocation; + + // remember the explicit constructor call as an orphan completion node + this.assistNode = call; + this.lastCheckPoint = call.sourceEnd + 1; + this.isOrphanCompletionNode = true; + return true; + } else { + // creates an allocation expression + CompletionOnQualifiedAllocationExpression allocExpr = new CompletionOnQualifiedAllocationExpression(); + allocExpr.arguments = arguments; + allocExpr.type = super.getTypeReference(0); // we don't want a completion node here, so call super + if (invocationType == QUALIFIED_ALLOCATION) { + allocExpr.enclosingInstance = this.expressionStack[qualifierExprPtr]; + } + // no source is going to be replaced + allocExpr.sourceStart = this.cursorLocation + 1; + allocExpr.sourceEnd = this.cursorLocation; + + // remember the allocation expression as an orphan completion node + this.assistNode = allocExpr; + this.lastCheckPoint = allocExpr.sourceEnd + 1; + this.isOrphanCompletionNode = true; + return true; + } + } + } + return false; +} +/** + * Checks if the completion is on a member access (ie. in an identifier following a dot). + * Returns whether we found a completion node. + */ +private boolean checkMemberAccess() { + if (this.previousToken == TokenNameDOT && this.qualifier > -1 && this.expressionPtr == this.qualifier) { + // the receiver is an expression + pushCompletionOnMemberAccessOnExpressionStack(false); + return true; + } + return false; +} +/** + * Checks if the completion is on a name reference. + * Returns whether we found a completion node. + */ +private boolean checkNameCompletion() { + /* + We didn't find any other completion, but the completion identifier is on the identifier stack, + so it can only be a completion on name. + Note that we allow the completion on a name even if nothing is expected (eg. foo() b[cursor] would + be a completion on 'b'). This policy gives more to the user than he/she would expect, but this + simplifies the problem. To fix this, the recovery must be changed to work at a 'statement' granularity + instead of at the 'expression' granularity as it does right now. + */ + + // NB: at this point the completion identifier is on the identifier stack + this.assistNode = getUnspecifiedReferenceOptimized(); + this.lastCheckPoint = this.assistNode.sourceEnd + 1; + this.isOrphanCompletionNode = true; + return true; +} +/** + * Checks if the completion is in the context of a method and on the type of one of its arguments + * Returns whether we found a completion node. + */ +private boolean checkRecoveredMethod() { + if (currentElement instanceof RecoveredMethod){ + /* check if current awaiting identifier is the completion identifier */ + if (this.indexOfAssistIdentifier() < 0) return false; + + /* check if on line with an error already - to avoid completing inside + illegal type names e.g. int[ */ + if (lastErrorEndPosition <= cursorLocation+1 + && scanner.getLineNumber(lastErrorEndPosition) + == scanner.getLineNumber(((CompletionScanner)scanner).completedIdentifierStart)){ + return false; + } + RecoveredMethod recoveredMethod = (RecoveredMethod)currentElement; + /* only consider if inside method header */ + if (!recoveredMethod.foundOpeningBrace + && lastIgnoredToken == -1) { + //if (rParenPos < lParenPos){ // inside arguments + this.assistNode = this.getTypeReference(0); + this.lastCheckPoint = this.assistNode.sourceEnd + 1; + this.isOrphanCompletionNode = true; + return true; + } + } + return false; +} +/** + * Checks if the completion is in the context of a type and on a type reference in this type. + * Persists the identifier into a fake field return type + * Returns whether we found a completion node. + */ +private boolean checkRecoveredType() { + if (currentElement instanceof RecoveredType){ + /* check if current awaiting identifier is the completion identifier */ + if (this.indexOfAssistIdentifier() < 0) return false; + + /* check if on line with an error already - to avoid completing inside + illegal type names e.g. int[ */ + if ((lastErrorEndPosition <= cursorLocation+1) + && scanner.getLineNumber(lastErrorEndPosition) + == scanner.getLineNumber(((CompletionScanner)scanner).completedIdentifierStart)){ + return false; + } + RecoveredType recoveredType = (RecoveredType)currentElement; + /* filter out cases where scanner is still inside type header */ + if (recoveredType.foundOpeningBrace) { + this.assistNode = this.getTypeReference(0); + this.lastCheckPoint = this.assistNode.sourceEnd + 1; + this.isOrphanCompletionNode = true; + return true; + } + } + return false; +} +/* + * Check whether about to shift beyond the completion token. + * If so, depending on the context, a special node might need to be created + * and attached to the existing recovered structure so as to be remember in the + * resulting parsed structure. + */ +public void completionIdentifierCheck(){ + + if (checkRecoveredType()) return; + if (checkRecoveredMethod()) return; + + // if not in a method in non diet mode and if not inside a field initializer, only record references attached to types + if (!(this.inMethodStack[this.inMethodPtr] && !this.diet) + && !insideFieldInitialization()) return; + + /* + In some cases, the completion identifier may not have yet been consumed, + e.g. int.[cursor] + This is because the grammar does not allow any (empty) identifier to follow + a base type. We thus have to manually force the identifier to be consumed + (i.e. pushed). + */ + if (assistIdentifier() == null && this.currentToken == TokenNameIdentifier) { // Test below copied from CompletionScanner.getCurrentIdentifierSource() + if (cursorLocation < this.scanner.startPosition && this.scanner.currentPosition == this.scanner.startPosition){ // fake empty identifier got issued + this.pushIdentifier(); + } else if (cursorLocation+1 >= this.scanner.startPosition && cursorLocation < this.scanner.currentPosition){ + this.pushIdentifier(); + } + } + + // check for different scenarii + try { + // no need to go further if we found a non empty completion node + // (we still need to store labels though) + if (this.assistNode != null) { + // however inside an invocation, the completion identifier may already have been consumed into an empty name + // completion, so this check should be before we check that we are at the cursor location + if (!isEmptyNameCompletion() || checkInvocation()) return; + } + + // no need to check further if we are not at the cursor location + if (this.indexOfAssistIdentifier() < 0) return; + + if (checkClassInstanceCreation()) return; + if (checkCatchClause()) return; + if (checkMemberAccess()) return; + if (checkClassLiteralAccess()) return; + + // if the completion was not on an empty name, it can still be inside an invocation (eg. this.fred("abc"[cursor]) + // (NB: Put this check before checkNameCompletion() because the selector of the invocation can be on the identifier stack) + if (checkInvocation()) return; + + if (checkNameCompletion()) return; + } finally { + storeLabelsIfNeeded(); + } +} +protected void consumeCaseLabel() { + Expression caseExpression = this.expressionStack[this.expressionPtr]; + if (caseExpression instanceof SingleNameReference || caseExpression instanceof QualifiedNameReference) { + // label counter was wrongly incremented in consumeToken + if (this.labelCounterPtr >= 0) this.labelCounterStack[this.labelCounterPtr]--; + } + super.consumeCaseLabel(); +} +protected void consumeClassHeaderExtends() { + this.nextTypeReferenceIsClass = true; + super.consumeClassHeaderExtends(); + this.nextTypeReferenceIsClass = false; +} +protected void consumeClassTypeElt() { + this.nextTypeReferenceIsException = true; + super.consumeClassTypeElt(); + this.nextTypeReferenceIsException = false; +} +protected void consumeConditionalExpression(int op) { + Expression valueIfTrue = this.expressionStack[this.expressionPtr - 1]; + if (valueIfTrue instanceof SingleNameReference || valueIfTrue instanceof QualifiedNameReference) { + // label counter was wrongly incremented in consumeToken + if (this.labelCounterPtr >= 0) this.labelCounterStack[this.labelCounterPtr]--; + } + super.consumeConditionalExpression(op); +} +protected void consumeConstructorBody() { + super.consumeConstructorBody(); + this.labelCounterPtr--; + if (this.blockInvocationPtr >= 0) this.blockInvocationPtr--; +} +protected void consumeConstructorHeader() { + super.consumeConstructorHeader(); + pushBlockInvocationPtr(); +} +protected void consumeConstructorHeaderName() { + + /* no need to take action if not inside assist identifiers */ + if (indexOfAssistIdentifier() < 0) { + super.consumeConstructorHeaderName(); + return; + } + + /* force to start recovering in order to get fake field behavior */ + if (currentElement == null){ + this.hasReportedError = true; // do not report any error + } + this.restartRecovery = true; +} +protected void consumeEnterVariable() { + identifierPtr--; + identifierLengthPtr--; + + boolean isLocalDeclaration = nestedMethod[nestedType] != 0; + int variableIndex = variablesCounter[nestedType]; + int extendedDimension = intStack[intPtr + 1]; + + if(isLocalDeclaration || indexOfAssistIdentifier() < 0 || variableIndex != 0 || extendedDimension != 0) { + identifierPtr++; + identifierLengthPtr++; + super.consumeEnterVariable(); + } else { + restartRecovery = true; + + // recovery + if (currentElement != null) { + int nameSourceStart = (int)(identifierPositionStack[identifierPtr] >>> 32); + intPtr--; + + TypeReference type = getTypeReference(intStack[intPtr--]); + intPtr--; + + if (!(currentElement instanceof RecoveredType) + && (currentToken == TokenNameDOT + || (scanner.getLineNumber(type.sourceStart) + != scanner.getLineNumber(nameSourceStart)))){ + lastCheckPoint = nameSourceStart; + restartRecovery = true; + return; + } + + FieldDeclaration completionFieldDecl = new CompletionOnFieldType(type, false); + completionFieldDecl.modifiers = intStack[intPtr--]; + assistNode = completionFieldDecl; + lastCheckPoint = type.sourceEnd + 1; + currentElement = currentElement.add(completionFieldDecl, 0); + lastIgnoredToken = -1; + } + } +} +protected void consumeExitVariableWithInitialization() { + super.consumeExitVariableWithInitialization(); + + // does not keep the initialization if completion is not inside + AbstractVariableDeclaration variable = (AbstractVariableDeclaration) astStack[astPtr]; + if (cursorLocation + 1 < variable.initialization.sourceStart || + cursorLocation > variable.initialization.sourceEnd) { + variable.initialization = null; + } +} + +/* + * Copy of code from superclass with the following change: + * If the cursor location is on the field access, then create a + * CompletionOnMemberAccess instead. + */ +protected void consumeFieldAccess(boolean isSuperAccess) { + // FieldAccess ::= Primary '.' 'Identifier' + // FieldAccess ::= 'super' '.' 'Identifier' + + // potential receiver is being poped, so reset potential receiver + this.invocationType = NO_RECEIVER; + + if (this.indexOfAssistIdentifier() < 0) { + super.consumeFieldAccess(isSuperAccess); + } else { + this.pushCompletionOnMemberAccessOnExpressionStack(isSuperAccess); + } +} + +protected void consumeFormalParameter() { + if (this.indexOfAssistIdentifier() < 0) { + super.consumeFormalParameter(); + } else { + + identifierLengthPtr--; + char[] name = identifierStack[identifierPtr]; + long namePositions = identifierPositionStack[identifierPtr--]; + TypeReference type = getTypeReference(intStack[intPtr--] + intStack[intPtr--]); + intPtr -= 2; + Argument arg = + new CompletionOnArgumentName( + name, + namePositions, + type, + intStack[intPtr + 1] & ~AccDeprecated); // modifiers + pushOnAstStack(arg); + + assistNode = arg; + this.lastCheckPoint = (int) namePositions; + isOrphanCompletionNode = true; + + /* if incomplete method header, listLength counter will not have been reset, + indicating that some arguments are available on the stack */ + listLength++; + } +} +protected void consumeInterfaceType() { + this.nextTypeReferenceIsInterface = true; + super.consumeInterfaceType(); + this.nextTypeReferenceIsInterface = false; +} +protected void consumeMethodHeaderName() { + if(this.indexOfAssistIdentifier() < 0) { + identifierPtr--; + identifierLengthPtr--; + if(this.indexOfAssistIdentifier() != 0) { + identifierPtr++; + identifierLengthPtr++; + super.consumeMethodHeaderName(); + } else { + restartRecovery = true; + + // recovery + if (currentElement != null) { + //name + char[] selector = identifierStack[identifierPtr + 1]; + long selectorSource = identifierPositionStack[identifierPtr + 1]; + + //type + TypeReference type = getTypeReference(intStack[intPtr--]); + ((CompletionOnSingleTypeReference)type).isCompletionNode = false; + //modifiers + int declarationSourceStart = intStack[intPtr--]; + int modifiers = intStack[intPtr--]; + + if(scanner.getLineNumber(type.sourceStart) != scanner.getLineNumber((int) (selectorSource >>> 32))) { + FieldDeclaration completionFieldDecl = new CompletionOnFieldType(type, false); + completionFieldDecl.modifiers = modifiers; + assistNode = completionFieldDecl; + lastCheckPoint = type.sourceEnd + 1; + currentElement = currentElement.add(completionFieldDecl, 0); + lastIgnoredToken = -1; + } else { + CompletionOnMethodReturnType md = new CompletionOnMethodReturnType(type, this.compilationUnit.compilationResult); + md.selector = selector; + md.declarationSourceStart = declarationSourceStart; + md.modifiers = modifiers; + md.bodyStart = lParenPos+1; + listLength = 0; // initialize listLength before reading parameters/throws + assistNode = md; + this.lastCheckPoint = md.bodyStart; + currentElement = currentElement.add(md, 0); + lastIgnoredToken = -1; + } + } + } + } else { + // MethodHeaderName ::= Modifiersopt Type 'Identifier' '(' + CompletionOnMethodName md = new CompletionOnMethodName(this.compilationUnit.compilationResult); + + //name + md.selector = identifierStack[identifierPtr]; + long selectorSource = identifierPositionStack[identifierPtr--]; + //type + md.returnType = getTypeReference(intStack[intPtr--]); + //modifiers + md.declarationSourceStart = intStack[intPtr--]; + md.modifiers = intStack[intPtr--]; + + //highlight starts at selector start + md.sourceStart = (int) (selectorSource >>> 32); + md.selectorEnd = (int) selectorSource; + pushOnAstStack(md); + md.sourceEnd = lParenPos; + md.bodyStart = lParenPos+1; + listLength = 0; // initialize listLength before reading parameters/throws + + this.assistNode = md; + this.lastCheckPoint = md.sourceEnd; + // recovery + if (currentElement != null){ + if (currentElement instanceof RecoveredType + //|| md.modifiers != 0 + || (scanner.getLineNumber(md.returnType.sourceStart) + == scanner.getLineNumber(md.sourceStart))){ + lastCheckPoint = md.bodyStart; + currentElement = currentElement.add(md, 0); + lastIgnoredToken = -1; + } else { + lastCheckPoint = md.sourceStart; + restartRecovery = true; + } + } + } +} + + +protected void consumeMethodBody() { + super.consumeMethodBody(); + this.labelCounterPtr--; + if (this.blockInvocationPtr >= 0) this.blockInvocationPtr--; +} + +protected void consumeMethodHeader() { + super.consumeMethodHeader(); + pushBlockInvocationPtr(); +} +protected void consumeModifiers() { + super.consumeModifiers(); + // save from stack values + this.lastModifiersStart = intStack[intPtr]; + this.lastModifiers = intStack[intPtr-1]; +} +protected void consumeNestedMethod() { + super.consumeNestedMethod(); + this.pushNewLabelCounter(); +} +protected void consumeStatementLabel() { + super.consumeStatementLabel(); + if (this.labelCounterPtr >= 0) this.labelCounterStack[this.labelCounterPtr]--; +} +protected void consumeToken(int token) { + int previous = this.previousToken; + int previousIdentifierPtr = this.previousIdentifierPtr; + super.consumeToken(token); + + // if in field initializer (directly or not), on the completion identifier and not in recovery mode yet + // then position end of file at cursor location (so that we have the same behavior as + // in method bodies) + if (token == TokenNameIdentifier + && this.identifierStack[this.identifierPtr] == assistIdentifier() + && this.currentElement == null + && this.insideFieldInitialization()) { + this.scanner.eofPosition = cursorLocation < Integer.MAX_VALUE ? cursorLocation+1 : cursorLocation; + } + + // if in a method or if in a field initializer + if (this.inMethodStack[this.inMethodPtr] || this.inFieldInitializationStack[this.inFieldInitializationPtr]) { + switch (token) { + case TokenNameDOT: + switch (previous) { +// case TokenNamethis: // eg. this[.]fred() +// this.invocationType = EXPLICIT_RECEIVER; +// break; +// case TokenNamesuper: // eg. super[.]fred() +// this.invocationType = SUPER_RECEIVER; +// break; + case TokenNameIdentifier: // eg. bar[.]fred() + if (!this.betweenNewAndLeftBraket) { // eg. not new z.y[.]X() + if (this.identifierPtr != previousIdentifierPtr) { // if identifier has been consumed, eg. this.x[.]fred() + this.invocationType = EXPLICIT_RECEIVER; + } else { + this.invocationType = NAME_RECEIVER; + } + } + break; + } + break; + case TokenNameIdentifier: + if (previous == TokenNameDOT) { // eg. foo().[fred]() + // if current identifier is the empty completion one + if (identifierStack[identifierPtr] == CompletionScanner.EmptyCompletionIdentifier){ + this.completionBehindDot = true; + } + if (this.invocationType != SUPER_RECEIVER // eg. not super.[fred]() + && this.invocationType != NAME_RECEIVER // eg. not bar.[fred]() + && this.invocationType != ALLOCATION // eg. not new foo.[Bar]() + && this.invocationType != QUALIFIED_ALLOCATION) { // eg. not fred().new foo.[Bar]() + + this.invocationType = EXPLICIT_RECEIVER; + this.qualifier = this.expressionPtr; + } + } + break; + case TokenNamenew: + this.betweenNewAndLeftBraket = true; + this.qualifier = this.expressionPtr; // NB: even if there is no qualification, set it to the expression ptr so that the number of arguments are correctly computed + if (previous == TokenNameDOT) { // eg. fred().[new] X() + this.invocationType = QUALIFIED_ALLOCATION; + } else { // eg. [new] X() + this.invocationType = ALLOCATION; + } + break; +// case TokenNamethis: +// if (previous == TokenNameDOT) { // eg. fred().[this]() +// this.invocationType = QUALIFIED_ALLOCATION; +// this.qualifier = this.expressionPtr; +// } +// break; +// case TokenNamesuper: +// if (previous == TokenNameDOT) { // eg. fred().[super]() +// this.invocationType = QUALIFIED_ALLOCATION; +// this.qualifier = this.expressionPtr; +// } +// break; +// case TokenNamecatch: +// this.betweenCatchAndRightParen = true; +// break; + case TokenNameLPAREN: + this.betweenNewAndLeftBraket = false; + this.bracketDepth++; + if (this.invocationType == NO_RECEIVER || this.invocationType == NAME_RECEIVER) { + this.qualifier = this.expressionPtr; // remenber the last expression so that arguments are correctly computed + } + switch (previous) { + case TokenNameIdentifier: // eg. fred[(]) or foo.fred[(]) + this.pushOnInvocationStacks(this.invocationType, this.qualifier); + this.invocationType = NO_RECEIVER; + break; +// case TokenNamethis: // explicit constructor invocation, eg. this[(]1, 2) +// this.pushOnInvocationStacks( +// (this.invocationType == QUALIFIED_ALLOCATION) ? QUALIFIED_ALLOCATION : ALLOCATION, +// this.qualifier); +// this.invocationType = NO_RECEIVER; +// break; +// case TokenNamesuper: // explicit constructor invocation, eg. super[(]1, 2) +// this.pushOnInvocationStacks( +// (this.invocationType == QUALIFIED_ALLOCATION) ? QUALIFIED_ALLOCATION : ALLOCATION, +// this.qualifier); +// this.invocationType = NO_RECEIVER; +// break; + } + break; + case TokenNameLBRACE: + this.betweenNewAndLeftBraket = false; + this.bracketDepth++; + this.pushBlockInvocationPtr(); + break; + case TokenNameLBRACKET: + this.betweenNewAndLeftBraket = false; + this.bracketDepth++; + break; + case TokenNameRBRACE: + this.bracketDepth--; + if (this.blockInvocationPtr >= 0) this.blockInvocationPtr--; + break; + case TokenNameRBRACKET: + this.bracketDepth--; + break; + case TokenNameRPAREN: + this.betweenCatchAndRightParen = false; + this.bracketDepth--; + break; + case TokenNameCOLON: + if (previous == TokenNameIdentifier) { + if (this.labelCounterPtr >= 0) this.labelCounterStack[this.labelCounterPtr]++; + } + break; +// case TokenNamethrow: +// this.throwBracketDepth= bracketDepth; +// break; + } + } +} +/** + * Return whether the given ast node contains the completion node. + */ +private boolean containsCompletionNode(AstNode ast) { + if (this.assistNode == null || ast instanceof Literal) { + return false; + } + if (this.assistNode == ast) { + return true; + } + if (ast instanceof Reference || ast instanceof TypeReference) { + return ast == this.assistNode; + } + if (ast instanceof Assignment) { + Assignment assign = (Assignment)ast; + return containsCompletionNode(assign.lhs) || containsCompletionNode(assign.expression); + } + if (ast instanceof UnaryExpression) { + UnaryExpression unary = (UnaryExpression)ast; + return containsCompletionNode(unary.expression); + } + if (ast instanceof BinaryExpression) { + BinaryExpression binary = (BinaryExpression)ast; + return containsCompletionNode(binary.left) || containsCompletionNode(binary.right); + } + if (ast instanceof InstanceOfExpression) { + InstanceOfExpression instanceOfExpr = (InstanceOfExpression)ast; + return containsCompletionNode(instanceOfExpr.expression) || containsCompletionNode(instanceOfExpr.type); + } + if (ast instanceof ConditionalExpression) { + ConditionalExpression conditional = (ConditionalExpression)ast; + return containsCompletionNode(conditional.condition) || containsCompletionNode(conditional.valueIfTrue) || containsCompletionNode(conditional.valueIfFalse); + } + if (ast instanceof AllocationExpression) { + AllocationExpression alloc = (AllocationExpression)ast; + return containsCompletionNode(alloc.type); + } + if (ast instanceof CastExpression) { + CastExpression cast = (CastExpression)ast; + return containsCompletionNode(cast.expression) || containsCompletionNode(cast.type); + } + if (ast instanceof ExplicitConstructorCall) { + ExplicitConstructorCall call = (ExplicitConstructorCall)ast; + Expression[] arguments = call.arguments; + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + if (containsCompletionNode(arguments[i])) { + return true; + } + } + return false; + } + } + return false; +} +public ImportReference createAssistImportReference(char[][] tokens, long[] positions){ + return new CompletionOnImportReference(tokens, positions); +} +public ImportReference createAssistPackageReference(char[][] tokens, long[] positions){ + return new CompletionOnPackageReference(tokens, positions); +} +public NameReference createQualifiedAssistNameReference(char[][] previousIdentifiers, char[] name, long[] positions){ + return new CompletionOnQualifiedNameReference( + previousIdentifiers, + name, + positions); +} +public TypeReference createQualifiedAssistTypeReference(char[][] previousIdentifiers, char[] name, long[] positions){ + return this.betweenCatchAndRightParen || this.nextTypeReferenceIsException // check for exception scenario + ? new CompletionOnQualifiedExceptionReference( + previousIdentifiers, + name, + positions) + : this.nextTypeReferenceIsInterface + ? new CompletionOnQualifiedInterfaceReference( + previousIdentifiers, + name, + positions) + : this.nextTypeReferenceIsClass + ? new CompletionOnQualifiedClassReference( + previousIdentifiers, + name, + positions) + : new CompletionOnQualifiedTypeReference( + previousIdentifiers, + name, + positions); +} +public NameReference createSingleAssistNameReference(char[] name, long position) { + return new CompletionOnSingleNameReference(name, position); +} +public TypeReference createSingleAssistTypeReference(char[] name, long position) { + return this.betweenCatchAndRightParen || this.nextTypeReferenceIsException // check for exception scenario + ? new CompletionOnExceptionReference(name, position) + : this.nextTypeReferenceIsInterface + ? new CompletionOnInterfaceReference(name, position) + : this.nextTypeReferenceIsClass + ? new CompletionOnClassReference(name, position) + : new CompletionOnSingleTypeReference(name, position); +} +public CompilationUnitDeclaration dietParse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int cursorLocation) { + + this.cursorLocation = cursorLocation; + CompletionScanner completionScanner = (CompletionScanner)this.scanner; + completionScanner.completionIdentifier = null; + completionScanner.cursorLocation = cursorLocation; + return this.dietParse(sourceUnit, compilationResult); +} +/* + * Flush parser/scanner state regarding to code assist + */ +public void flushAssistState() { + + super.flushAssistState(); + this.isOrphanCompletionNode = false; + CompletionScanner completionScanner = (CompletionScanner)this.scanner; + completionScanner.completedIdentifierStart = 0; + completionScanner.completedIdentifierEnd = -1; +} +protected NameReference getUnspecifiedReferenceOptimized() { + if (this.identifierLengthStack[this.identifierLengthPtr] > 1) { // reducing a qualified name + // potential receiver is being poped, so reset potential receiver + this.invocationType = NO_RECEIVER; + } + return super.getUnspecifiedReferenceOptimized(); +} +/** + * Return whether the given ast node has information interresting for code completion. + */ +private boolean hasCompletionInformation(AstNode ast) { + return ( + ast instanceof AbstractMethodDeclaration || + ast instanceof AbstractVariableDeclaration || + ast instanceof LabeledStatement || + ast instanceof TypeDeclaration); +} +public void initialize() { + super.initialize(); + this.initializeForBlockStatements(); + this.labelCounterPtr = -1; +} +/* + * Initializes the state of the parser that is about to go for BlockStatements. + */ +private void initializeForBlockStatements() { + this.previousToken = -1; + this.previousIdentifierPtr = -1; + this.completionBehindDot = false; + this.betweenNewAndLeftBraket = false; + this.betweenCatchAndRightParen = false; + this.bracketDepth = 0; + this.throwBracketDepth = -1; + this.invocationType = NO_RECEIVER; + this.qualifier = -1; + this.blockInvocationPtr = -1; +} +public void initializeScanner(){ + this.scanner = new CompletionScanner(this.assertMode); +} +/** + * Returns whether the completion is just after an array type + * eg. String[].[cursor] + */ +private boolean isAfterArrayType() { + // TBD: The following relies on the fact that array dimensions are small: it says that if the + // top of the intStack is less than 11, then it must be a dimension + // (smallest position of array type in a compilation unit is 11 as in "class X{Y[]") + if ((this.intPtr > -1) && (this.intStack[this.intPtr] < 11)) { + return true; + } + return false; +} +private boolean isEmptyNameCompletion() { + return + this.assistNode != null && + this.assistNode instanceof CompletionOnSingleNameReference && + (((CompletionOnSingleNameReference)this.assistNode).token.length == 0); +} +public CompilationUnitDeclaration parse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int cursorLocation) { + + this.cursorLocation = cursorLocation; + CompletionScanner completionScanner = (CompletionScanner)this.scanner; + completionScanner.completionIdentifier = null; + completionScanner.cursorLocation = cursorLocation; + return this.parse(sourceUnit, compilationResult); +} +/* + * Prepares the state of the parser to go for BlockStatements. + */ +protected void prepareForBlockStatements() { + super.prepareForBlockStatements(); + this.initializeForBlockStatements(); +} +protected void pushBlockInvocationPtr() { + try { + this.blockInvocationStack[++this.blockInvocationPtr] = this.invocationPtr+1; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = this.blockInvocationStack.length; + int[] oldStack = this.blockInvocationStack; + this.blockInvocationStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldStack, 0, this.blockInvocationStack, 0, oldStackLength); + this.blockInvocationStack[this.blockInvocationPtr] = this.invocationPtr+1; + } +} +/** + * Creates a completion on member access node and push it + * on the expression stack. + */ +private void pushCompletionOnMemberAccessOnExpressionStack(boolean isSuperAccess) { + char[] source = identifierStack[identifierPtr]; + long pos = identifierPositionStack[identifierPtr--]; + CompletionOnMemberAccess fr = new CompletionOnMemberAccess(source, pos); + this.assistNode = fr; + this.lastCheckPoint = fr.sourceEnd + 1; + identifierLengthPtr--; + if (isSuperAccess) { //considerates the fieldReference beginning at the 'super' .... + fr.sourceStart = intStack[intPtr--]; + fr.receiver = new SuperReference(fr.sourceStart, endPosition); + pushOnExpressionStack(fr); + } else { //optimize push/pop + if ((fr.receiver = expressionStack[expressionPtr]).isThis()) { //fieldreference begins at the this + fr.sourceStart = fr.receiver.sourceStart; + } + expressionStack[expressionPtr] = fr; + } +} +protected void pushNewLabelCounter() { + try { + this.labelCounterStack[++this.labelCounterPtr] = 0; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = this.labelCounterStack.length; + int[] oldStack = this.labelCounterStack; + this.labelCounterStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldStack, 0, this.labelCounterStack, 0, oldStackLength); + this.labelCounterStack[this.labelCounterPtr] = 0; + } +} +/** + * Pushes the given invocation type (one of the invocation type constants) on the invocation type stack, + * and the given qualifier (an expression pointer to the expression stack) on the qualifier stack. + */ +protected void pushOnInvocationStacks(int invocationType, int qualifierExprPtr) { + // NB: invocationPtr has already been incremented by a call to pushOnSelectorStack() + try { + this.invocationTypeStack[this.invocationPtr] = invocationType; + this.qualifierStack[this.invocationPtr] = qualifierExprPtr; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = this.invocationTypeStack.length; + int oldInvocationTypeStack[] = this.invocationTypeStack; + int oldQualifierStack[] = this.qualifierStack; + this.invocationTypeStack = new int[oldStackLength + StackIncrement]; + this.qualifierStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldInvocationTypeStack, 0, this.invocationTypeStack, 0, oldStackLength); + System.arraycopy(oldQualifierStack, 0, this.qualifierStack, 0, oldStackLength); + this.invocationTypeStack[this.invocationPtr] = invocationType; + this.qualifierStack[this.invocationPtr] = qualifierExprPtr; + } +} +public void recordCompletionOnReference(){ + + if (currentElement instanceof RecoveredType){ + RecoveredType recoveredType = (RecoveredType)currentElement; + + /* filter out cases where scanner is still inside type header */ + if (!recoveredType.foundOpeningBrace) return; + + /* generate a pseudo field with a completion on type reference */ + currentElement.add( + new CompletionOnFieldType(this.getTypeReference(0), false), 0); + return; + } + if (!diet) return; // only record references attached to types + +} +protected void reportSyntaxError(int act, int currentKind, int stateStackTop) { + + /* Intercept error state on EOF inside method bodies, due to + cursor location being used as an EOF position. + */ + if (!diet && currentToken == TokenNameEOF) return; + super.reportSyntaxError(act, currentKind, stateStackTop); +} +/* + * Reset internal state after completion is over + */ + +public void reset() { + super.reset(); + this.cursorLocation = 0; +} +/* + * Reset internal state after completion is over + */ + +public void resetAfterCompletion() { + this.cursorLocation = 0; + this.flushAssistState(); +} +/* + * Reset context so as to resume to regular parse loop + * If unable to reset for resuming, answers false. + * + * Move checkpoint location, reset internal stacks and + * decide which grammar goal is activated. + */ +protected boolean resumeAfterRecovery() { + if (this.assistNode != null) { + /* if reached [eof] inside method body, but still inside nested type, + or inside a field initializer, should continue in diet mode until + the end of the method body or compilation unit */ + if ((scanner.eofPosition == cursorLocation+1) + && (!(referenceContext instanceof CompilationUnitDeclaration) + || insideFieldInitialization())) { + + /* disabled since does not handle possible field/message refs, i.e. Obj[ASSIST HERE]ect.registerNatives() + // consume extra tokens which were part of the qualified reference + // so that the replaced source comprises them as well + if (this.assistNode instanceof NameReference){ + int oldEof = scanner.eofPosition; + scanner.eofPosition = currentElement.topElement().sourceEnd()+1; + scanner.currentPosition = this.cursorLocation+1; + int token = -1; + try { + do { + // first token might not have to be a dot + if (token >= 0 || !this.completionBehindDot){ + if ((token = scanner.getNextToken()) != TokenNameDOT) break; + } + if ((token = scanner.getNextToken()) != TokenNameIdentifier) break; + this.assistNode.sourceEnd = scanner.currentPosition - 1; + } while (token != TokenNameEOF); + } catch (InvalidInputException e){ + } finally { + scanner.eofPosition = oldEof; + } + } + */ + /* restart in diet mode for finding sibling constructs */ + if (currentElement.enclosingType() != null){ + lastCheckPoint = this.assistNode.sourceEnd+1; + int end = currentElement.topElement().sourceEnd(); + scanner.eofPosition = end < Integer.MAX_VALUE ? end + 1 : end; + } else { + this.resetStacks(); + return false; + } + } + } + return super.resumeAfterRecovery(); +} +public void setAssistIdentifier(char[] assistIdent){ + ((CompletionScanner)scanner).completionIdentifier = assistIdent; +} +/** + * Stores the labels left on the identifier stack if they have not been stored yet. + */ +private void storeLabelsIfNeeded() { +// int counter = this.labelCounterPtr >= 0 ? this.labelCounterStack[this.labelCounterPtr] : 0; +// if (this.labels == null && this.identifierPtr >= 0) { +// this.labels = new char[counter][]; +// System.arraycopy(this.identifierStack, this.identifierPtr - counter + 1, this.labels, 0, counter); +// } +// this.identifierPtr -= counter; +// this.identifierLengthPtr -= counter; // labels have not been concatenated yet +} +/* + * Update recovery state based on current parser/scanner state + */ +protected void updateRecoveryState() { + + /* expose parser state to recovery state */ + currentElement.updateFromParserState(); + + /* may be able to retrieve completionNode as an orphan, and then attach it */ + this.completionIdentifierCheck(); + this.attachOrphanCompletionNode(); + + // if an assist node has been found and a recovered element exists, + // mark enclosing blocks as to be preserved + if (this.assistNode != null && this.currentElement != null) { + currentElement.preserveEnclosingBlocks(); + } + + /* check and update recovered state based on current token, + this action is also performed when shifting token after recovery + got activated once. + */ + this.recoveryTokenCheck(); +} + +protected LocalDeclaration createLocalDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) { + if (this.indexOfAssistIdentifier() < 0) { + return super.createLocalDeclaration(initialization, name, sourceStart, sourceEnd); + } else { + CompletionOnLocalName local = new CompletionOnLocalName(initialization, name, sourceStart, sourceEnd); + this.assistNode = local; + this.lastCheckPoint = sourceEnd + 1; + return local; + } +} + +protected FieldDeclaration createFieldDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) { + if (this.indexOfAssistIdentifier() < 0) { + return super.createFieldDeclaration(initialization, name, sourceStart, sourceEnd); + } else { + CompletionOnFieldName field = new CompletionOnFieldName(initialization, name, sourceStart, sourceEnd); + this.assistNode = field; + this.lastCheckPoint = sourceEnd + 1; + return field; + } +} + +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionScanner.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionScanner.java new file mode 100644 index 0000000..d3b2156 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionScanner.java @@ -0,0 +1,707 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/* + * Scanner aware of a cursor location so as to discard trailing portions of identifiers + * containing the cursor location. + * + * Cursor location denotes the position of the last character behind which completion + * got requested: + * -1 means completion at the very beginning of the source + * 0 means completion behind the first character + * n means completion behind the n-th character + */ +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.parser.Scanner; + +public class CompletionScanner extends Scanner { + + public char[] completionIdentifier; + public int cursorLocation; + + /* Source positions of the completedIdentifier + * if inside actual identifier, end goes to the actual identifier + * end, i.e. beyond cursor location + */ + public int completedIdentifierStart = 0; + public int completedIdentifierEnd = -1; + + public static final char[] EmptyCompletionIdentifier = {}; +public CompletionScanner(boolean assertMode) { + super(false, false, false, assertMode); +} +/* + * Truncate the current identifier if it is containing the cursor location. Since completion is performed + * on an identifier prefix. + * + */ +public char[] getCurrentIdentifierSource() { + + if (completionIdentifier == null){ + if (cursorLocation < startPosition && currentPosition == startPosition){ // fake empty identifier got issued + // remember actual identifier positions + completedIdentifierStart = startPosition; + completedIdentifierEnd = completedIdentifierStart - 1; + return completionIdentifier = EmptyCompletionIdentifier; + } + if (cursorLocation+1 >= startPosition && cursorLocation < currentPosition){ + // remember actual identifier positions + completedIdentifierStart = startPosition; + completedIdentifierEnd = currentPosition - 1; + if (withoutUnicodePtr != 0){ // check unicode scenario + System.arraycopy(withoutUnicodeBuffer, 1, completionIdentifier = new char[withoutUnicodePtr], 0, withoutUnicodePtr); + } else { + int length = cursorLocation + 1 - startPosition; + // no char[] sharing around completionIdentifier, we want it to be unique so as to use identity checks + System.arraycopy(source, startPosition, (completionIdentifier = new char[length]), 0, length); + } + return completionIdentifier; + } + } + return super.getCurrentIdentifierSource(); +} +/* + * Identifier splitting for unicodes. + * Only store the current unicode if we did not pass the cursorLocation. + * Note: this does not handle cases where the cursor is in the middle of a unicode + */ +public boolean getNextCharAsJavaIdentifierPart() { + + int temp = currentPosition; + try { + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1, c2, c3, c4; + int unicodeSize = 6; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + unicodeSize++; + } + + if (((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0) + || ((c2 = Character.getNumericValue(source[currentPosition++])) > 15 || c2 < 0) + || ((c3 = Character.getNumericValue(source[currentPosition++])) > 15 || c3 < 0) + || ((c4 = Character.getNumericValue(source[currentPosition++])) > 15 || c4 < 0)) { + currentPosition = temp; + return false; + } + + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + if (!Character.isJavaIdentifierPart(currentCharacter)) { + currentPosition = temp; + return false; + } + + //need the unicode buffer + if (withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + withoutUnicodePtr = currentPosition - unicodeSize - startPosition; + System.arraycopy( + source, + startPosition, + withoutUnicodeBuffer, + 1, + withoutUnicodePtr); + } + if (temp < cursorLocation && cursorLocation < currentPosition-1){ + throw new InvalidCursorLocation(InvalidCursorLocation.NO_COMPLETION_INSIDE_UNICODE); + } + // store the current unicode, only if we did not pass the cursorLocation + // Note: this does not handle cases where the cursor is in the middle of a unicode + if ((completionIdentifier != null) + || (startPosition <= cursorLocation+1 && cursorLocation >= currentPosition-1)){ + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + return true; + } //-------------end unicode traitement-------------- + else { + if (!Character.isJavaIdentifierPart(currentCharacter)) { + currentPosition = temp; + return false; + } + + if (withoutUnicodePtr != 0){ + // store the current unicode, only if we did not pass the cursorLocation + // Note: this does not handle cases where the cursor is in the middle of a unicode + if ((completionIdentifier != null) + || (startPosition <= cursorLocation+1 && cursorLocation >= currentPosition-1)){ + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + return true; + } + } catch (IndexOutOfBoundsException e) { + currentPosition = temp; + return false; + } +} +public int getNextToken() throws InvalidInputException { + + this.wasAcr = false; + if (diet) { + jumpOverMethodBody(); + diet = false; + return currentPosition > source.length ? TokenNameEOF : TokenNameRBRACE; + } + try { + while (true) { //loop for jumping over comments + withoutUnicodePtr = 0; + //start with a new token (even comment written with unicode ) + + // ---------Consume white space and handles startPosition--------- + int whiteStart = currentPosition; + boolean isWhiteSpace; + do { + startPosition = currentPosition; + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + isWhiteSpace = jumpOverUnicodeWhiteSpace(); + } else { + if (recordLineSeparator + && ((currentCharacter == '\r') || (currentCharacter == '\n'))) + pushLineSeparator(); + isWhiteSpace = + (currentCharacter == ' ') || Character.isWhitespace(currentCharacter); + } + /* completion requesting strictly inside blanks */ + if ((whiteStart != currentPosition) + //&& (previousToken == TokenNameDOT) + && (completionIdentifier == null) + && (whiteStart <= cursorLocation+1) + && (cursorLocation < startPosition) + && !Character.isJavaIdentifierStart(currentCharacter)){ + currentPosition = startPosition; // for next token read + return TokenNameIdentifier; + } + } while (isWhiteSpace); + if (tokenizeWhiteSpace && (whiteStart != currentPosition - 1)) { + // reposition scanner in case we are interested by spaces as tokens + currentPosition--; + startPosition = whiteStart; + return TokenNameWHITESPACE; + } + //little trick to get out in the middle of a source computation + if (currentPosition > eofPosition){ + /* might be completing at eof (e.g. behind a dot) */ + if (completionIdentifier == null && + startPosition == cursorLocation + 1){ + currentPosition = startPosition; // for being detected as empty free identifier + return TokenNameIdentifier; + } + return TokenNameEOF; + } + + // ---------Identify the next token------------- + + switch (currentCharacter) { + case '(' : + return TokenNameLPAREN; + case ')' : + return TokenNameRPAREN; + case '{' : + return TokenNameLBRACE; + case '}' : + return TokenNameRBRACE; + case '[' : + return TokenNameLBRACKET; + case ']' : + return TokenNameRBRACKET; + case ';' : + return TokenNameSEMICOLON; + case ',' : + return TokenNameCOMMA; + case '.' : + if (startPosition <= cursorLocation + && cursorLocation < currentPosition){ + return TokenNameDOT; // completion inside .<|>12 + } + if (getNextCharAsDigit()) + return scanNumber(true); + return TokenNameDOT; + case '+' : + { + int test; + if ((test = getNextChar('+', '=')) == 0) + return TokenNamePLUS_PLUS; + if (test > 0) + return TokenNamePLUS_EQUAL; + return TokenNamePLUS; + } + case '-' : + { + int test; + if ((test = getNextChar('-', '=')) == 0) + return TokenNameMINUS_MINUS; + if (test > 0) + return TokenNameMINUS_EQUAL; + return TokenNameMINUS; + } + case '~' : + return TokenNameTWIDDLE; + case '!' : + if (getNextChar('=')) + return TokenNameNOT_EQUAL; + return TokenNameNOT; + case '*' : + if (getNextChar('=')) + return TokenNameMULTIPLY_EQUAL; + return TokenNameMULTIPLY; + case '%' : + if (getNextChar('=')) + return TokenNameREMAINDER_EQUAL; + return TokenNameREMAINDER; + case '<' : + { + int test; + if ((test = getNextChar('=', '<')) == 0) + return TokenNameLESS_EQUAL; + if (test > 0) { + if (getNextChar('=')) + return TokenNameLEFT_SHIFT_EQUAL; + return TokenNameLEFT_SHIFT; + } + return TokenNameLESS; + } + case '>' : + { + int test; + if ((test = getNextChar('=', '>')) == 0) + return TokenNameGREATER_EQUAL; + if (test > 0) { + if ((test = getNextChar('=', '>')) == 0) + return TokenNameRIGHT_SHIFT_EQUAL; + if (test > 0) { + if (getNextChar('=')) + return TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL; + return TokenNameUNSIGNED_RIGHT_SHIFT; + } + return TokenNameRIGHT_SHIFT; + } + return TokenNameGREATER; + } + case '=' : + if (getNextChar('=')) + return TokenNameEQUAL_EQUAL; + return TokenNameEQUAL; + case '&' : + { + int test; + if ((test = getNextChar('&', '=')) == 0) + return TokenNameAND_AND; + if (test > 0) + return TokenNameAND_EQUAL; + return TokenNameAND; + } + case '|' : + { + int test; + if ((test = getNextChar('|', '=')) == 0) + return TokenNameOR_OR; + if (test > 0) + return TokenNameOR_EQUAL; + return TokenNameOR; + } + case '^' : + if (getNextChar('=')) + return TokenNameXOR_EQUAL; + return TokenNameXOR; + case '?' : + return TokenNameQUESTION; + case ':' : + return TokenNameCOLON; + case '\'' : + { + int test; + if ((test = getNextChar('\n', '\r')) == 0) { + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + if (test > 0) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 3; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\'') { + currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + } + if (getNextChar('\'')) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 3; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\'') { + currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + } + if (getNextChar('\\')) + scanEscapeCharacter(); + else { // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + } + if (getNextChar('\'')) + return TokenNameCharacterLiteral; + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 20; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\'') { + currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHARACTER_CONSTANT); + case '"' : + try { + // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + + while (currentCharacter != '"') { + /**** \r and \n are not valid in string literals ****/ + if ((currentCharacter == '\n') || (currentCharacter == '\r')) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 50; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\"') { + currentPosition += lookAhead + 1; + break; + } + } + throw new InvalidInputException(INVALID_CHAR_IN_STRING); + } + if (currentCharacter == '\\') { + int escapeSize = currentPosition; + boolean backSlashAsUnicodeInString = unicodeAsBackSlash; + //scanEscapeCharacter make a side effect on this value and we need the previous value few lines down this one + scanEscapeCharacter(); + escapeSize = currentPosition - escapeSize; + if (withoutUnicodePtr == 0) { + //buffer all the entries that have been left aside.... + withoutUnicodePtr = currentPosition - escapeSize - 1 - startPosition; + System.arraycopy( + source, + startPosition, + withoutUnicodeBuffer, + 1, + withoutUnicodePtr); + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } else { //overwrite the / in the buffer + withoutUnicodeBuffer[withoutUnicodePtr] = currentCharacter; + if (backSlashAsUnicodeInString) { //there are TWO \ in the stream where only one is correct + withoutUnicodePtr--; + } + } + } + // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + + } + } catch (IndexOutOfBoundsException e) { + throw new InvalidInputException(UNTERMINATED_STRING); + } catch (InvalidInputException e) { + if (e.getMessage().equals(INVALID_ESCAPE)) { + // relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed + for (int lookAhead = 0; lookAhead < 50; lookAhead++) { + if (currentPosition + lookAhead == source.length) + break; + if (source[currentPosition + lookAhead] == '\n') + break; + if (source[currentPosition + lookAhead] == '\"') { + currentPosition += lookAhead + 1; + break; + } + } + + } + throw e; // rethrow + } + if (startPosition <= cursorLocation && cursorLocation <= currentPosition-1){ + throw new InvalidCursorLocation(InvalidCursorLocation.NO_COMPLETION_INSIDE_STRING); + } + return TokenNameStringLiteral; + case '/' : + { + int test; + if ((test = getNextChar('/', '*')) == 0) { //line comment + try { //get the next char + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + + //handle the \\u case manually into comment + if (currentCharacter == '\\') { + if (source[currentPosition] == '\\') + currentPosition++; + } //jump over the \\ + while (currentCharacter != '\r' && currentCharacter != '\n') { + //get the next char + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + //handle the \\u case manually into comment + if (currentCharacter == '\\') { + if (source[currentPosition] == '\\') + currentPosition++; + } //jump over the \\ + } + recordComment(false); + if (startPosition <= cursorLocation && cursorLocation < currentPosition-1){ + throw new InvalidCursorLocation(InvalidCursorLocation.NO_COMPLETION_INSIDE_COMMENT); + } + if (recordLineSeparator + && ((currentCharacter == '\r') || (currentCharacter == '\n'))) + pushLineSeparator(); + if (tokenizeComments) { + currentPosition--; // reset one character behind + return TokenNameCOMMENT_LINE; + } + } catch (IndexOutOfBoundsException e) { //an eof will them be generated + if (tokenizeComments) { + currentPosition--; // reset one character behind + return TokenNameCOMMENT_LINE; + } + } + break; + } + if (test > 0) { //traditional and annotation comment + boolean isJavadoc = false, star = false; + // consume next character + unicodeAsBackSlash = false; + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + getNextUnicodeChar(); + } else { + if (withoutUnicodePtr != 0) { + withoutUnicodeBuffer[++withoutUnicodePtr] = currentCharacter; + } + } + + if (currentCharacter == '*') { + isJavadoc = true; + star = true; + } + if (recordLineSeparator + && ((currentCharacter == '\r') || (currentCharacter == '\n'))) + pushLineSeparator(); + try { //get the next char + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + //handle the \\u case manually into comment + if (currentCharacter == '\\') { + if (source[currentPosition] == '\\') + currentPosition++; + } //jump over the \\ + // empty comment is not a javadoc /**/ + if (currentCharacter == '/') { + isJavadoc = false; + } + //loop until end of comment */ + while ((currentCharacter != '/') || (!star)) { + if (recordLineSeparator + && ((currentCharacter == '\r') || (currentCharacter == '\n'))) + pushLineSeparator(); + star = currentCharacter == '*'; + //get next char + if (((currentCharacter = source[currentPosition++]) == '\\') + && (source[currentPosition] == 'u')) { + //-------------unicode traitement ------------ + int c1 = 0, c2 = 0, c3 = 0, c4 = 0; + currentPosition++; + while (source[currentPosition] == 'u') { + currentPosition++; + } + if ((c1 = Character.getNumericValue(source[currentPosition++])) > 15 + || c1 < 0 + || (c2 = Character.getNumericValue(source[currentPosition++])) > 15 + || c2 < 0 + || (c3 = Character.getNumericValue(source[currentPosition++])) > 15 + || c3 < 0 + || (c4 = Character.getNumericValue(source[currentPosition++])) > 15 + || c4 < 0) { + throw new InvalidInputException(INVALID_UNICODE_ESCAPE); + } else { + currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); + } + } + //handle the \\u case manually into comment + if (currentCharacter == '\\') { + if (source[currentPosition] == '\\') + currentPosition++; + } //jump over the \\ + } + recordComment(isJavadoc); + if (startPosition <= cursorLocation && cursorLocation < currentPosition-1){ + throw new InvalidCursorLocation(InvalidCursorLocation.NO_COMPLETION_INSIDE_COMMENT); + } + if (tokenizeComments) { + if (isJavadoc) + return TokenNameCOMMENT_JAVADOC; + return TokenNameCOMMENT_BLOCK; + } + } catch (IndexOutOfBoundsException e) { + throw new InvalidInputException(UNTERMINATED_COMMENT); + } + break; + } + if (getNextChar('=')) + return TokenNameDIVIDE_EQUAL; + return TokenNameDIVIDE; + } + case '\u001a' : + if (atEnd()) + return TokenNameEOF; + //the atEnd may not be if source is only some part of a real (external) stream + throw new InvalidInputException("Ctrl-Z"); //$NON-NLS-1$ + + default : + if (Character.isJavaIdentifierStart(currentCharacter)) + return scanIdentifierOrKeyword(); + if (Character.isDigit(currentCharacter)) + return scanNumber(false); + return TokenNameERROR; + } + } + } //-----------------end switch while try-------------------- + catch (IndexOutOfBoundsException e) { + } + /* might be completing at very end of file (e.g. behind a dot) */ + if (completionIdentifier == null && + startPosition == cursorLocation + 1){ + currentPosition = startPosition; // for being detected as empty free identifier + return TokenNameIdentifier; + } + return TokenNameEOF; +} +/* + * In case we actually read a keyword, but the cursor is located inside, + * we pretend we read an identifier. + */ +public int scanIdentifierOrKeyword() throws InvalidInputException { + + int id = super.scanIdentifierOrKeyword(); + + // convert completed keyword into an identifier + if (id != TokenNameIdentifier + && startPosition <= cursorLocation+1 + && cursorLocation < currentPosition){ + return TokenNameIdentifier; + } + return id; +} +public int scanNumber(boolean dotPrefix) throws InvalidInputException { + + int token = super.scanNumber(dotPrefix); + + // consider completion just before a number to be ok, will insert before it + if (startPosition <= cursorLocation && cursorLocation < currentPosition){ + throw new InvalidCursorLocation(InvalidCursorLocation.NO_COMPLETION_INSIDE_NUMBER); + } + return token; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/InvalidCursorLocation.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/InvalidCursorLocation.java new file mode 100644 index 0000000..295dd81 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/InvalidCursorLocation.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.complete; + +/** + * Thrown whenever cursor location is not inside a consistent token + * i.e. inside a string, number, unicode, comments etc... + */ +public class InvalidCursorLocation extends RuntimeException { + + public String irritant; + + /* Possible irritants */ + public static final String NO_COMPLETION_INSIDE_UNICODE = "No Completion Inside Unicode"; //$NON-NLS-1$ + public static final String NO_COMPLETION_INSIDE_COMMENT = "No Completion Inside Comment"; //$NON-NLS-1$ + public static final String NO_COMPLETION_INSIDE_STRING = "No Completion Inside String"; //$NON-NLS-1$ + public static final String NO_COMPLETION_INSIDE_NUMBER = "No Completion Inside Number"; //$NON-NLS-1$ + +public InvalidCursorLocation(String irritant){ + this.irritant = irritant; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/impl/AssistOptions.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/impl/AssistOptions.java new file mode 100644 index 0000000..76fbddd --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/impl/AssistOptions.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.impl; + +import java.util.Map; + +public class AssistOptions { + /** + * Option IDs + */ + public static final String OPTION_PerformVisibilityCheck = + "org.eclipse.jdt.core.codeComplete.visibilityCheck"; //$NON-NLS-1$ + public static final String OPTION_ForceImplicitQualification = + "org.eclipse.jdt.core.codeComplete.forceImplicitQualification"; //$NON-NLS-1$ + public static final String ENABLED = "enabled"; //$NON-NLS-1$ + public static final String DISABLED = "disabled"; //$NON-NLS-1$ + + public boolean checkVisibility = false; + public boolean forceImplicitQualification = false; + + /** + * Initializing the assist options with default settings + */ + public AssistOptions() { + } + + /** + * Initializing the assist options with external settings + */ + public AssistOptions(Map settings) { + if (settings == null) + return; + + // filter options which are related to the assist component + Object[] entries = settings.entrySet().toArray(); + for (int i = 0, max = entries.length; i < max; i++) { + Map.Entry entry = (Map.Entry) entries[i]; + if (!(entry.getKey() instanceof String)) + continue; + if (!(entry.getValue() instanceof String)) + continue; + String optionID = (String) entry.getKey(); + String optionValue = (String) entry.getValue(); + + if (optionID.equals(OPTION_PerformVisibilityCheck)) { + if (optionValue.equals(ENABLED)) { + this.checkVisibility = true; + } else + if (optionValue.equals(DISABLED)) { + this.checkVisibility = false; + } + continue; + } else if (optionID.equals(OPTION_ForceImplicitQualification)) { + if (optionValue.equals(ENABLED)) { + this.forceImplicitQualification = true; + } else + if (optionValue.equals(DISABLED)) { + this.forceImplicitQualification = false; + } + continue; + } + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/impl/AssistParser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/impl/AssistParser.java new file mode 100644 index 0000000..b97679f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/impl/AssistParser.java @@ -0,0 +1,1009 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.impl; + +/* + * Parser extension for code assist task + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.AstNode; +import net.sourceforge.phpdt.internal.compiler.ast.Block; +import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ExplicitConstructorCall; +import net.sourceforge.phpdt.internal.compiler.ast.Expression; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; +import net.sourceforge.phpdt.internal.compiler.ast.Initializer; +import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.MessageSend; +import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.NameReference; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.parser.Parser; +import net.sourceforge.phpdt.internal.compiler.parser.RecoveredElement; +import net.sourceforge.phpdt.internal.compiler.parser.RecoveredField; +import net.sourceforge.phpdt.internal.compiler.parser.RecoveredInitializer; +import net.sourceforge.phpdt.internal.compiler.parser.RecoveredMethod; +import net.sourceforge.phpdt.internal.compiler.parser.RecoveredType; +import net.sourceforge.phpdt.internal.compiler.parser.RecoveredUnit; +import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; + +public abstract class AssistParser extends Parser { + + public AstNode assistNode; + public boolean isOrphanCompletionNode; + + /* recovery */ + int[] blockStarts = new int[30]; + + // the previous token read by the scanner + protected int previousToken; + + // the index in the identifier stack of the previous identifier + protected int previousIdentifierPtr; + + // the stacks of selectors for invocations (ie. method invocations, allocation expressions and + // explicit constructor invocations) + // the selector stack contains pointers to the identifier stack or one of the selector constants below + protected int invocationPtr; + protected int[] selectorStack = new int[StackIncrement]; + + // selector constants + protected static final int THIS_CONSTRUCTOR = -1; + protected static final int SUPER_CONSTRUCTOR = -2; + + // whether the parser is in a field initializer + // (false is pushed each time a new type is entered, + // it is changed to true when the initializer is entered, + // it is changed back to false when the initializer is exited, + // and it is poped when the type is exited) + protected int inFieldInitializationPtr; + protected boolean[] inFieldInitializationStack = new boolean[StackIncrement]; + + // whether the parser is in a method, constructor or initializer + // (false is pushed each time a new type is entered, + // it is changed to true when the method is entered, + // it is changed back to false when the method is exited, + // and it is poped when the type is exited) + protected int inMethodPtr; + protected boolean[] inMethodStack = new boolean[StackIncrement]; +public AssistParser(ProblemReporter problemReporter, boolean assertMode) { + super(problemReporter, true, assertMode); +} +public abstract char[] assistIdentifier(); +public int bodyEnd(AbstractMethodDeclaration method){ + return method.declarationSourceEnd; +} +public int bodyEnd(Initializer initializer){ + return initializer.declarationSourceEnd; +} +/* + * Build initial recovery state. + * Recovery state is inferred from the current state of the parser (reduced node stack). + */ +public RecoveredElement buildInitialRecoveryState(){ + + /* recovery in unit structure */ + if (referenceContext instanceof CompilationUnitDeclaration){ + RecoveredElement element = super.buildInitialRecoveryState(); + flushAssistState(); + initInMethodAndInFieldInitializationStack(element); + return element; + } + + /* recovery in method body */ + lastCheckPoint = 0; + + RecoveredElement element = null; + if (referenceContext instanceof AbstractMethodDeclaration){ + element = new RecoveredMethod((AbstractMethodDeclaration) referenceContext, null, 0, this); + lastCheckPoint = ((AbstractMethodDeclaration) referenceContext).bodyStart; + } else { + /* Initializer bodies are parsed in the context of the type declaration, we must thus search it inside */ + if (referenceContext instanceof TypeDeclaration){ + TypeDeclaration type = (TypeDeclaration) referenceContext; + for (int i = 0; i < type.fields.length; i++){ + FieldDeclaration field = type.fields[i]; + if (!field.isField() + && field.declarationSourceStart <= scanner.initialPosition + && scanner.initialPosition <= field.declarationSourceEnd + && scanner.eofPosition <= field.declarationSourceEnd+1){ + element = new RecoveredInitializer((Initializer) field, null, 1, this); + lastCheckPoint = field.declarationSourceStart; + break; + } + } + } + } + + if (element == null) return element; + + /* add initial block */ + Block block = new Block(0); + int lastStart = blockStarts[0]; + block.sourceStart = lastStart; + element = element.add(block, 1); + int blockIndex = 1; // ignore first block start, since manually rebuilt here + + for(int i = 0; i <= astPtr; i++){ + AstNode node = astStack[i]; + + /* check for intermediate block creation, so recovery can properly close them afterwards */ + int nodeStart = node.sourceStart; + for (int j = blockIndex; j <= realBlockPtr; j++){ + if (blockStarts[j] > nodeStart){ + blockIndex = j; // shift the index to the new block + break; + } + if (blockStarts[j] != lastStart){ // avoid multiple block if at same position + block = new Block(0); + block.sourceStart = lastStart = blockStarts[j]; + element = element.add(block, 1); + } + blockIndex = j+1; // shift the index to the new block + } + if (node instanceof LocalDeclaration){ + LocalDeclaration local = (LocalDeclaration) node; + if (local.declarationSourceEnd == 0){ + element = element.add(local, 0); + if (local.initialization == null){ + lastCheckPoint = local.sourceEnd + 1; + } else { + lastCheckPoint = local.initialization.sourceEnd + 1; + } + } else { + element = element.add(local, 0); + lastCheckPoint = local.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof AbstractMethodDeclaration){ + AbstractMethodDeclaration method = (AbstractMethodDeclaration) node; + if (method.declarationSourceEnd == 0){ + element = element.add(method, 0); + lastCheckPoint = method.bodyStart; + } else { + element = element.add(method, 0); + lastCheckPoint = method.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof Initializer){ + Initializer initializer = (Initializer) node; + if (initializer.declarationSourceEnd == 0){ + element = element.add(initializer, 1); + lastCheckPoint = initializer.bodyStart; + } else { + element = element.add(initializer, 0); + lastCheckPoint = initializer.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof FieldDeclaration){ + FieldDeclaration field = (FieldDeclaration) node; + if (field.declarationSourceEnd == 0){ + element = element.add(field, 0); + if (field.initialization == null){ + lastCheckPoint = field.sourceEnd + 1; + } else { + lastCheckPoint = field.initialization.sourceEnd + 1; + } + } else { + element = element.add(field, 0); + lastCheckPoint = field.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof TypeDeclaration){ + TypeDeclaration type = (TypeDeclaration) node; + if (type.declarationSourceEnd == 0){ + element = element.add(type, 0); + lastCheckPoint = type.bodyStart; + } else { + element = element.add(type, 0); + lastCheckPoint = type.declarationSourceEnd + 1; + } + continue; + } + if (node instanceof ImportReference){ + ImportReference importRef = (ImportReference) node; + element = element.add(importRef, 0); + lastCheckPoint = importRef.declarationSourceEnd + 1; + } + } + if (this.currentToken == TokenNameRBRACE) { + this.currentToken = 0; // closing brace has already been taken care of + } + + /* might need some extra block (after the last reduced node) */ + int pos = this.assistNode == null ? lastCheckPoint : this.assistNode.sourceStart; + for (int j = blockIndex; j <= realBlockPtr; j++){ + if ((blockStarts[j] < pos) && (blockStarts[j] != lastStart)){ // avoid multiple block if at same position + block = new Block(0); + block.sourceStart = lastStart = blockStarts[j]; + element = element.add(block, 1); + } + } + + initInMethodAndInFieldInitializationStack(element); + return element; +} +protected void consumeClassBodyDeclarationsopt() { + super.consumeClassBodyDeclarationsopt(); + this.inFieldInitializationPtr--; + this.inMethodPtr--; +} +protected void consumeClassBodyopt() { + super.consumeClassBodyopt(); + this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer +} +protected void consumeClassHeader() { + super.consumeClassHeader(); + this.pushNotInInitializer(); + this.pushNotInMethod(); +} +protected void consumeConstructorBody() { + super.consumeConstructorBody(); + this.inMethodStack[this.inMethodPtr] = false; +} +protected void consumeConstructorHeader() { + super.consumeConstructorHeader(); + this.inMethodStack[this.inMethodPtr] = true; +} +protected void consumeEmptyClassBodyDeclarationsopt() { + super.consumeEmptyClassBodyDeclarationsopt(); + this.inFieldInitializationPtr--; + this.inMethodPtr--; +} +protected void consumeEnterAnonymousClassBody() { + super.consumeEnterAnonymousClassBody(); + this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer + this.pushNotInInitializer(); + this.pushNotInMethod(); +} +protected void consumeExplicitConstructorInvocation(int flag, int recFlag) { + super.consumeExplicitConstructorInvocation(flag, recFlag); + this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer +} +protected void consumeForceNoDiet() { + super.consumeForceNoDiet(); + // if we are not in a method (ie. we are not in a local variable initializer) + // then we are entering a field initializer + if (!this.inMethodStack[this.inMethodPtr]) { + this.inFieldInitializationStack[this.inFieldInitializationPtr] = true; + } +} +protected void consumeInterfaceHeader() { + super.consumeInterfaceHeader(); + this.pushNotInInitializer(); + this.pushNotInMethod(); +} +protected void consumeInterfaceMemberDeclarationsopt() { + super.consumeInterfaceMemberDeclarationsopt(); + this.inFieldInitializationPtr--; + this.inMethodPtr--; +} +protected void consumeMethodBody() { + super.consumeMethodBody(); + this.inMethodStack[this.inMethodPtr] = false; +} +protected void consumeMethodHeader() { + super.consumeMethodHeader(); + this.inMethodStack[this.inMethodPtr] = true; +} +protected void consumeMethodInvocationName() { + super.consumeMethodInvocationName(); + this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer + MessageSend messageSend = (MessageSend)expressionStack[expressionPtr]; + if (messageSend == assistNode){ + this.lastCheckPoint = messageSend.sourceEnd + 1; + } +} +protected void consumeMethodInvocationPrimary() { + super.consumeMethodInvocationPrimary(); + this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer + MessageSend messageSend = (MessageSend)expressionStack[expressionPtr]; + if (messageSend == assistNode){ + this.lastCheckPoint = messageSend.sourceEnd + 1; + } +} +protected void consumeMethodInvocationSuper() { + super.consumeMethodInvocationSuper(); + this.invocationPtr--; // NB: This can be decremented below -1 only if in diet mode and not in field initializer + MessageSend messageSend = (MessageSend)expressionStack[expressionPtr]; + if (messageSend == assistNode){ + this.lastCheckPoint = messageSend.sourceEnd + 1; + } +} +protected void consumeNestedMethod() { + super.consumeNestedMethod(); + this.inMethodStack[this.inMethodPtr] = true; +} +protected void consumeOpenBlock() { + // OpenBlock ::= $empty + + super.consumeOpenBlock(); + try { + blockStarts[realBlockPtr] = scanner.startPosition; + } catch (IndexOutOfBoundsException e) { + //realBlockPtr is correct + int oldStackLength = blockStarts.length; + int oldStack[] = blockStarts; + blockStarts = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldStack, 0, blockStarts, 0, oldStackLength); + blockStarts[realBlockPtr] = scanner.startPosition; + } +} +protected void consumePackageDeclarationName() { + // PackageDeclarationName ::= 'package' Name + /* build an ImportRef build from the last name + stored in the identifier stack. */ + + int index; + + /* no need to take action if not inside assist identifiers */ + if ((index = indexOfAssistIdentifier()) < 0) { + super.consumePackageDeclarationName(); + return; + } + /* retrieve identifiers subset and whole positions, the assist node positions + should include the entire replaced source. */ + int length = identifierLengthStack[identifierLengthPtr]; + char[][] subset = identifierSubSet(index+1); // include the assistIdentifier + identifierLengthPtr--; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + + /* build specific assist node on package statement */ + ImportReference reference = this.createAssistPackageReference(subset, positions); + assistNode = reference; + this.lastCheckPoint = reference.sourceEnd + 1; + compilationUnit.currentPackage = reference; + + if (currentToken == TokenNameSEMICOLON){ + reference.declarationSourceEnd = scanner.currentPosition - 1; + } else { + reference.declarationSourceEnd = (int) positions[length-1]; + } + //endPosition is just before the ; + reference.declarationSourceStart = intStack[intPtr--]; + // flush annotations defined prior to import statements + reference.declarationSourceEnd = this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd); + + // recovery + if (currentElement != null){ + lastCheckPoint = reference.declarationSourceEnd+1; + restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeRestoreDiet() { + super.consumeRestoreDiet(); + // if we are not in a method (ie. we were not in a local variable initializer) + // then we are exiting a field initializer + if (!this.inMethodStack[this.inMethodPtr]) { + this.inFieldInitializationStack[this.inFieldInitializationPtr] = false; + } +} +protected void consumeSingleTypeImportDeclarationName() { + // SingleTypeImportDeclarationName ::= 'import' Name + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + int index; + + /* no need to take action if not inside assist identifiers */ + if ((index = indexOfAssistIdentifier()) < 0) { + super.consumeSingleTypeImportDeclarationName(); + return; + } + /* retrieve identifiers subset and whole positions, the assist node positions + should include the entire replaced source. */ + int length = identifierLengthStack[identifierLengthPtr]; + char[][] subset = identifierSubSet(index+1); // include the assistIdentifier + identifierLengthPtr--; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + + /* build specific assist node on import statement */ + ImportReference reference = this.createAssistImportReference(subset, positions); + assistNode = reference; + this.lastCheckPoint = reference.sourceEnd + 1; + + pushOnAstStack(reference); + + if (currentToken == TokenNameSEMICOLON){ + reference.declarationSourceEnd = scanner.currentPosition - 1; + } else { + reference.declarationSourceEnd = (int) positions[length-1]; + } + //endPosition is just before the ; + reference.declarationSourceStart = intStack[intPtr--]; + // flush annotations defined prior to import statements + reference.declarationSourceEnd = this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd); + + // recovery + if (currentElement != null){ + lastCheckPoint = reference.declarationSourceEnd+1; + currentElement = currentElement.add(reference, 0); + lastIgnoredToken = -1; + restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +protected void consumeStaticInitializer() { + super.consumeStaticInitializer(); + this.inMethodStack[this.inMethodPtr] = false; +} +protected void consumeStaticOnly() { + super.consumeStaticOnly(); + this.inMethodStack[this.inMethodPtr] = true; +} +protected void consumeToken(int token) { + super.consumeToken(token); + // register message send selector only if inside a method or if looking at a field initializer + // and if the current token is an open parenthesis + if ((this.inMethodStack[this.inMethodPtr] || this.inFieldInitializationStack[this.inFieldInitializationPtr]) && token == TokenNameLPAREN) { + switch (this.previousToken) { + case TokenNameIdentifier: + this.pushOnSelectorStack(this.identifierPtr); + break; +// case TokenNamethis: // explicit constructor invocation, eg. this(1, 2) +// this.pushOnSelectorStack(THIS_CONSTRUCTOR); +// break; +// case TokenNamesuper: // explicit constructor invocation, eg. super(1, 2) +// this.pushOnSelectorStack(SUPER_CONSTRUCTOR); +// break; + } + } + this.previousToken = token; + if (token == TokenNameIdentifier) { + this.previousIdentifierPtr = this.identifierPtr; + } +} +protected void consumeTypeImportOnDemandDeclarationName() { + // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*' + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + int index; + + /* no need to take action if not inside assist identifiers */ + if ((index = indexOfAssistIdentifier()) < 0) { + super.consumeTypeImportOnDemandDeclarationName(); + return; + } + /* retrieve identifiers subset and whole positions, the assist node positions + should include the entire replaced source. */ + int length = identifierLengthStack[identifierLengthPtr]; + char[][] subset = identifierSubSet(index+1); // include the assistIdentifier + identifierLengthPtr--; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + + /* build specific assist node on import statement */ + ImportReference reference = this.createAssistImportReference(subset, positions); + reference.onDemand = true; + assistNode = reference; + this.lastCheckPoint = reference.sourceEnd + 1; + + pushOnAstStack(reference); + + if (currentToken == TokenNameSEMICOLON){ + reference.declarationSourceEnd = scanner.currentPosition - 1; + } else { + reference.declarationSourceEnd = (int) positions[length-1]; + } + //endPosition is just before the ; + reference.declarationSourceStart = intStack[intPtr--]; + // flush annotations defined prior to import statements + reference.declarationSourceEnd = this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd); + + // recovery + if (currentElement != null){ + lastCheckPoint = reference.declarationSourceEnd+1; + currentElement = currentElement.add(reference, 0); + lastIgnoredToken = -1; + restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +public abstract ImportReference createAssistImportReference(char[][] tokens, long[] positions); +public abstract ImportReference createAssistPackageReference(char[][] tokens, long[] positions); +public abstract NameReference createQualifiedAssistNameReference(char[][] previousIdentifiers, char[] name, long[] positions); +public abstract TypeReference createQualifiedAssistTypeReference(char[][] previousIdentifiers, char[] name, long[] positions); +public abstract NameReference createSingleAssistNameReference(char[] name, long position); +public abstract TypeReference createSingleAssistTypeReference(char[] name, long position); +/* + * Flush parser/scanner state regarding to code assist + */ +public void flushAssistState(){ + this.assistNode = null; + this.isOrphanCompletionNode = false; + this.setAssistIdentifier(null); +} +/* + * Build specific type reference nodes in case the cursor is located inside the type reference + */ +protected TypeReference getTypeReference(int dim) { + + int index; + + /* no need to take action if not inside completed identifiers */ + if ((index = indexOfAssistIdentifier()) < 0) { + return super.getTypeReference(dim); + } + + /* retrieve identifiers subset and whole positions, the assist node positions + should include the entire replaced source. */ + int length = identifierLengthStack[identifierLengthPtr]; + char[][] subset = identifierSubSet(index); + identifierLengthPtr--; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + + /* build specific assist on type reference */ + TypeReference reference; + if (index == 0) { + /* assist inside first identifier */ + reference = this.createSingleAssistTypeReference( + assistIdentifier(), + positions[0]); + } else { + /* assist inside subsequent identifier */ + reference = this.createQualifiedAssistTypeReference( + subset, + assistIdentifier(), + positions); + } + assistNode = reference; + this.lastCheckPoint = reference.sourceEnd + 1; + return reference; +} +/* + * Copy of code from superclass with the following change: + * In the case of qualified name reference if the cursor location is on the + * qualified name reference, then create a CompletionOnQualifiedNameReference + * instead. + */ +protected NameReference getUnspecifiedReferenceOptimized() { + + int completionIndex; + + /* no need to take action if not inside completed identifiers */ + if ((completionIndex = indexOfAssistIdentifier()) < 0) { + return super.getUnspecifiedReferenceOptimized(); + } + + /* retrieve identifiers subset and whole positions, the completion node positions + should include the entire replaced source. */ + int length = identifierLengthStack[identifierLengthPtr]; + char[][] subset = identifierSubSet(completionIndex); + identifierLengthPtr--; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + + /* build specific completion on name reference */ + NameReference reference; + if (completionIndex == 0) { + /* completion inside first identifier */ + reference = this.createSingleAssistNameReference(assistIdentifier(), positions[0]); + } else { + /* completion inside subsequent identifier */ + reference = this.createQualifiedAssistNameReference(subset, assistIdentifier(), positions); + }; + reference.bits &= ~AstNode.RestrictiveFlagMASK; + reference.bits |= LOCAL | FIELD; + + assistNode = reference; + lastCheckPoint = reference.sourceEnd + 1; + return reference; +} +public void goForBlockStatementsopt() { + //tells the scanner to go for block statements opt parsing + + firstToken = TokenNameTWIDDLE; + scanner.recordLineSeparator = false; +} +public void goForConstructorBlockStatementsopt() { + //tells the scanner to go for constructor block statements opt parsing + + firstToken = TokenNameNOT; + scanner.recordLineSeparator = false; +} +/* + * Retrieve a partial subset of a qualified name reference up to the completion point. + * It does not pop the actual awaiting identifiers, so as to be able to retrieve position + * information afterwards. + */ +protected char[][] identifierSubSet(int subsetLength){ + + if (subsetLength == 0) return null; + + char[][] subset; + System.arraycopy( + identifierStack, + identifierPtr - identifierLengthStack[identifierLengthPtr] + 1, + (subset = new char[subsetLength][]), + 0, + subsetLength); + return subset; +} +/* + * Iterate the most recent group of awaiting identifiers (grouped for qualified name reference (eg. aa.bb.cc) + * so as to check whether one of them is the assist identifier. + * If so, then answer the index of the assist identifier (0 being the first identifier of the set). + * eg. aa(0).bb(1).cc(2) + * If no assist identifier was found, answers -1. + */ +protected int indexOfAssistIdentifier(){ + + if (identifierLengthPtr < 0){ + return -1; // no awaiting identifier + } + + char[] assistIdentifier ; + if ((assistIdentifier = this.assistIdentifier()) == null){ + return -1; // no assist identifier found yet + } + + // iterate awaiting identifiers backwards + int length = identifierLengthStack[identifierLengthPtr]; + for (int i = 0; i < length; i++){ + if (identifierStack[identifierPtr - i] == assistIdentifier){ + return length - i - 1; + } + } + // none of the awaiting identifiers is the completion one + return -1; +} +public void initialize() { + super.initialize(); + this.flushAssistState(); + this.invocationPtr = -1; + this.inMethodStack[this.inMethodPtr = 0] = false; + this.inFieldInitializationStack[this.inFieldInitializationPtr = 0] = false; + this.previousIdentifierPtr = -1; +} +public abstract void initializeScanner(); + +protected void initInMethodAndInFieldInitializationStack(RecoveredElement currentElement) { + + int length = currentElement.depth() + 1; + int ptr = length; + boolean[] methodStack = new boolean[length]; + boolean[] fieldInitializationStack = new boolean[length]; + boolean inMethod = false; + boolean inFieldInitializer = false; + + RecoveredElement element = currentElement; + while(element != null){ + if(element instanceof RecoveredMethod || + element instanceof RecoveredInitializer) { + if(element.parent == null) { + methodStack[--ptr] = true; + fieldInitializationStack[ptr] = false; + } + inMethod = true; + } else if(element instanceof RecoveredField){ + inFieldInitializer = element.sourceEnd() == 0; + } else if(element instanceof RecoveredType){ + methodStack[--ptr] = inMethod; + fieldInitializationStack[ptr] = inFieldInitializer; + + inMethod = false; + inFieldInitializer = false; + } else if(element instanceof RecoveredUnit) { + methodStack[--ptr] = false; + fieldInitializationStack[ptr] = false; + } + element = element.parent; + } + + inMethodPtr = length - ptr - 1; + inFieldInitializationPtr = inMethodPtr; + System.arraycopy(methodStack, ptr, inMethodStack, 0, inMethodPtr + 1); + System.arraycopy(fieldInitializationStack, ptr, inFieldInitializationStack, 0, inFieldInitializationPtr + 1); + +} + +/** + * Returns whether we are directly or indirectly inside a field initializer. + */ +protected boolean insideFieldInitialization() { + for (int i = this.inFieldInitializationPtr; i >= 0; i--) { + if (this.inFieldInitializationStack[i]) { + return true; + } + } + return false; +} +/** + * Parse the block statements inside the given method declaration and try to complete at the + * cursor location. + */ +public void parseBlockStatements(AbstractMethodDeclaration md, CompilationUnitDeclaration unit) { + if (md instanceof MethodDeclaration) { + parseBlockStatements((MethodDeclaration) md, unit); + } else if (md instanceof ConstructorDeclaration) { + parseBlockStatements((ConstructorDeclaration) md, unit); + } +} +/** + * Parse the block statements inside the given constructor declaration and try to complete at the + * cursor location. + */ +public void parseBlockStatements(ConstructorDeclaration cd, CompilationUnitDeclaration unit) { + //only parse the method body of cd + //fill out its statements + + //convert bugs into parse error + + initialize(); + + // simulate goForConstructorBody except that we don't want to balance brackets because they are not going to be balanced + goForConstructorBlockStatementsopt(); + + referenceContext = cd; + compilationUnit = unit; + + scanner.resetTo(cd.bodyStart, bodyEnd(cd)); + consumeNestedMethod(); + try { + parse(); + } catch (AbortCompilation ex) { + lastAct = ERROR_ACTION; + } +} +/** + * Parse the block statements inside the given initializer and try to complete at the + * cursor location. + */ +public void parseBlockStatements( + Initializer ini, + TypeDeclaration type, + CompilationUnitDeclaration unit) { + + initialize(); + + // simulate goForInitializer except that we don't want to balance brackets because they are not going to be balanced + goForBlockStatementsopt(); + + referenceContext = type; + compilationUnit = unit; + + scanner.resetTo(ini.sourceStart, bodyEnd(ini)); // just after the beginning { + consumeNestedMethod(); + try { + parse(); + } catch (AbortCompilation ex) { + lastAct = ERROR_ACTION; + } finally { + nestedMethod[nestedType]--; + } +} +/** + * Parse the block statements inside the given method declaration and try to complete at the + * cursor location. + */ +public void parseBlockStatements(MethodDeclaration md, CompilationUnitDeclaration unit) { + //only parse the method body of md + //fill out method statements + + //convert bugs into parse error + + if (md.isAbstract()) + return; + if (md.isNative()) + return; + if ((md.modifiers & AccSemicolonBody) != 0) + return; + + initialize(); + + // simulate goForMethodBody except that we don't want to balance brackets because they are not going to be balanced + goForBlockStatementsopt(); + + referenceContext = md; + compilationUnit = unit; + + scanner.resetTo(md.bodyStart, bodyEnd(md)); // reset the scanner to parser from { down to the cursor location + consumeNestedMethod(); + try { + parse(); + } catch (AbortCompilation ex) { + lastAct = ERROR_ACTION; + } finally { + nestedMethod[nestedType]--; + } +} +/* + * Prepares the state of the parser to go for BlockStatements. + */ +protected void prepareForBlockStatements() { + this.nestedMethod[this.nestedType = 0] = 1; + this.variablesCounter[this.nestedType] = 0; + this.realBlockStack[this.realBlockPtr = 1] = 0; + this.invocationPtr = -1; +} +/* + * Pushes 'false' on the inInitializerStack. + */ +protected void pushNotInInitializer() { + try { + this.inFieldInitializationStack[++this.inFieldInitializationPtr] = false; + } catch (IndexOutOfBoundsException e) { + //except in test's cases, it should never raise + int oldStackLength = this.inFieldInitializationStack.length; + System.arraycopy(this.inFieldInitializationStack , 0, (this.inFieldInitializationStack = new boolean[oldStackLength + StackIncrement]), 0, oldStackLength); + this.inFieldInitializationStack[this.inFieldInitializationPtr] = false; + } +} +/* + * Pushes 'false' on the inMethodStack. + */ +protected void pushNotInMethod() { + try { + this.inMethodStack[++this.inMethodPtr] = false; + } catch (IndexOutOfBoundsException e) { + //except in test's cases, it should never raise + int oldStackLength = this.inMethodStack.length; + System.arraycopy(this.inMethodStack , 0, (this.inMethodStack = new boolean[oldStackLength + StackIncrement]), 0, oldStackLength); + this.inMethodStack[this.inMethodPtr] = false; + } +} +/** + * Pushes the given the given selector (an identifier pointer to the identifier stack) on the selector stack. + */ +protected void pushOnSelectorStack(int selectorIdPtr) { + if (this.invocationPtr < -1) return; + try { + this.selectorStack[++this.invocationPtr] = selectorIdPtr; + } catch (IndexOutOfBoundsException e) { + int oldStackLength = this.selectorStack.length; + int oldSelectorStack[] = this.selectorStack; + this.selectorStack = new int[oldStackLength + StackIncrement]; + System.arraycopy(oldSelectorStack, 0, this.selectorStack, 0, oldStackLength); + this.selectorStack[this.invocationPtr] = selectorIdPtr; + } +} +public void reset(){ + this.flushAssistState(); +} +/* + * Reset context so as to resume to regular parse loop + */ +protected void resetStacks() { + super.resetStacks(); + this.inFieldInitializationStack[this.inFieldInitializationPtr = 0] = false; + this.inMethodStack[this.inMethodPtr = 0] = false; +} +/* + * Reset context so as to resume to regular parse loop + * If unable to reset for resuming, answers false. + * + * Move checkpoint location, reset internal stacks and + * decide which grammar goal is activated. + */ +protected boolean resumeAfterRecovery() { + + // reset internal stacks + astPtr = -1; + astLengthPtr = -1; + expressionPtr = -1; + expressionLengthPtr = -1; + identifierPtr = -1; + identifierLengthPtr = -1; + intPtr = -1; + dimensions = 0 ; + recoveredStaticInitializerStart = 0; + + // if in diet mode, reset the diet counter because we're going to restart outside an initializer. + if (diet) dietInt = 0; + + /* attempt to move checkpoint location */ + if (!this.moveRecoveryCheckpoint()) return false; + + initInMethodAndInFieldInitializationStack(currentElement); + + // only look for headers + if (referenceContext instanceof CompilationUnitDeclaration + || this.assistNode != null){ + + if(inMethodStack[inMethodPtr] && + insideFieldInitialization() && + this.assistNode == null + ){ + this.prepareForBlockStatements(); + goForBlockStatementsOrMethodHeaders(); + } else { + nestedMethod[nestedType = 0] = 0; + variablesCounter[nestedType] = 0; + realBlockStack[realBlockPtr = 0] = 0; + goForHeaders(); + diet = true; // passed this point, will not consider method bodies + } + return true; + } + if (referenceContext instanceof AbstractMethodDeclaration + || referenceContext instanceof TypeDeclaration){ + + if (currentElement instanceof RecoveredType){ + nestedMethod[nestedType = 0] = 0; + variablesCounter[nestedType] = 0; + realBlockStack[realBlockPtr = 0] = 0; + goForHeaders(); + } else { + this.prepareForBlockStatements(); + goForBlockStatementsOrMethodHeaders(); + } + return true; + } + // does not know how to restart + return false; +} +public abstract void setAssistIdentifier(char[] assistIdent); +/** + * If the given ast node is inside an explicit constructor call + * then wrap it with a fake constructor call. + * Returns the wrapped completion node or the completion node itself. + */ +protected AstNode wrapWithExplicitConstructorCallIfNeeded(AstNode ast) { + int selector; + if (ast != null && this.invocationPtr >= 0 && ast instanceof Expression && + (((selector = this.selectorStack[this.invocationPtr]) == THIS_CONSTRUCTOR) || + (selector == SUPER_CONSTRUCTOR))) { + ExplicitConstructorCall call = new ExplicitConstructorCall( + (selector == THIS_CONSTRUCTOR) ? + ExplicitConstructorCall.This : + ExplicitConstructorCall.Super + ); + call.arguments = new Expression[] {(Expression)ast}; + call.sourceStart = ast.sourceStart; + call.sourceEnd = ast.sourceEnd; + return call; + } else { + return ast; + } +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/impl/Engine.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/impl/Engine.java new file mode 100644 index 0000000..35a3dc9 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/impl/Engine.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.impl; + +import java.util.Map; + +import net.sourceforge.phpdt.internal.codeassist.ISearchableNameEnvironment; +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.env.*; + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; +import net.sourceforge.phpdt.internal.compiler.impl.*; + + +public abstract class Engine implements ITypeRequestor { + + public LookupEnvironment lookupEnvironment; + + protected CompilationUnitScope unitScope; + protected ISearchableNameEnvironment nameEnvironment; + + public AssistOptions options; + public CompilerOptions compilerOptions; + + public Engine(Map settings){ + this.options = new AssistOptions(settings); + this.compilerOptions = new CompilerOptions(settings); + } + + /** + * Add an additional binary type + */ + public void accept(IBinaryType binaryType, PackageBinding packageBinding) { + lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding); + } + + /** + * Add an additional compilation unit. + */ + public void accept(ICompilationUnit sourceUnit) { + CompilationResult result = new CompilationResult(sourceUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = + this.getParser().dietParse(sourceUnit, result); + + + lookupEnvironment.buildTypeBindings(parsedUnit); + lookupEnvironment.completeTypeBindings(parsedUnit, true); + } + + /** + * Add additional source types (the first one is the requested type, the rest is formed by the + * secondary types defined in the same compilation unit). + */ + public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding) { + CompilationResult result = + new CompilationResult(sourceTypes[0].getFileName(), 1, 1, this.compilerOptions.maxProblemsPerUnit); + CompilationUnitDeclaration unit = + SourceTypeConverter.buildCompilationUnit( + sourceTypes, + true, + true, + lookupEnvironment.problemReporter, + result); + + if (unit != null) { + lookupEnvironment.buildTypeBindings(unit); + lookupEnvironment.completeTypeBindings(unit, true); + } + } + + public abstract AssistParser getParser(); + + protected boolean mustQualifyType( + char[] packageName, + char[] typeName) { + + // If there are no types defined into the current CU yet. + if (unitScope == null) + return true; + + char[][] compoundPackageName = CharOperation.splitOn('.', packageName); + char[] readableTypeName = CharOperation.concat(packageName, typeName, '.'); + + if (CharOperation.equals(unitScope.fPackage.compoundName, compoundPackageName)) + return false; + + ImportBinding[] imports = unitScope.imports; + if (imports != null){ + for (int i = 0, length = imports.length; i < length; i++) { + if (imports[i].onDemand) { + if (CharOperation.equals(imports[i].compoundName, compoundPackageName)) { + for (int j = 0; j < imports.length; j++) { + if(i != j){ + if(imports[j].onDemand) { + if(nameEnvironment.findType(typeName, imports[j].compoundName) != null){ + return true; + } + } else { + if(CharOperation.equals(CharOperation.lastSegment(imports[j].readableName(), '.'), typeName)) { + return true; + } + } + } + } + return false; // how do you match p1.p2.A.* ? + } + + } else + + if (CharOperation.equals(imports[i].readableName(), readableTypeName)) { + return false; + } + } + } + return true; + } + + protected void parseMethod(CompilationUnitDeclaration unit, int position) { + for (int i = unit.types.length; --i >= 0;) { + TypeDeclaration type = unit.types[i]; + if (type.declarationSourceStart < position + && type.declarationSourceEnd >= position) { + getParser().scanner.setSource( + unit.compilationResult.compilationUnit.getContents()); + parseMethod(type, unit, position); + return; + } + } + } + + private void parseMethod( + TypeDeclaration type, + CompilationUnitDeclaration unit, + int position) { + //members + TypeDeclaration[] memberTypes = type.memberTypes; + if (memberTypes != null) { + for (int i = memberTypes.length; --i >= 0;) { + TypeDeclaration memberType = memberTypes[i]; + if (memberType.bodyStart > position) + continue; + if (memberType.declarationSourceEnd >= position) { + parseMethod(memberType, unit, position); + return; + } + } + } + //methods + AbstractMethodDeclaration[] methods = type.methods; + if (methods != null) { + for (int i = methods.length; --i >= 0;) { + AbstractMethodDeclaration method = methods[i]; + if (method.bodyStart > position) + continue; + if (method.declarationSourceEnd >= position) { + getParser().parseBlockStatements(method, unit); + return; + } + } + } + //initializers + FieldDeclaration[] fields = type.fields; + if (fields != null) { + for (int i = fields.length; --i >= 0;) { + if (!(fields[i] instanceof Initializer)) + continue; + Initializer initializer = (Initializer) fields[i]; + if (initializer.bodyStart > position) + continue; + if (initializer.declarationSourceEnd >= position) { + getParser().parseBlockStatements(initializer, type, unit); + return; + } + } + } + } + + protected void reset() { + lookupEnvironment.reset(); + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionNodeFound.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionNodeFound.java new file mode 100644 index 0000000..6d8a66f --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionNodeFound.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class SelectionNodeFound extends RuntimeException { + public Binding binding; +public SelectionNodeFound() { + this(null); // we found a problem in the selection node +} +public SelectionNodeFound(Binding binding) { + this.binding = binding; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnArgumentName.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnArgumentName.java new file mode 100644 index 0000000..06a6783 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnArgumentName.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +import net.sourceforge.phpdt.internal.compiler.ast.Argument; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class SelectionOnArgumentName extends Argument { + public SelectionOnArgumentName(char[] name , long posNom , TypeReference tr , int modifiers){ + super(name, posNom, tr, modifiers); + } + + public void resolve(BlockScope scope) { + super.resolve(scope); + throw new SelectionNodeFound(binding); + } + + public void bind(MethodScope scope, TypeBinding typeBinding, boolean used) { + super.bind(scope, typeBinding, used); + + throw new SelectionNodeFound(binding); + } + + public String toString(int tab) { + String s = tabString(tab); + s += " class X { + * void foo() { + * + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.*; + +public class SelectionOnExplicitConstructorCall extends ExplicitConstructorCall { +public SelectionOnExplicitConstructorCall(int accessMode) { + super(accessMode); +} +public void resolve(BlockScope scope) { + super.resolve(scope); + + // tolerate some error cases + if (binding == null || + !(binding.isValidBinding() || + binding.problemId() == ProblemReasons.NotVisible)) + throw new SelectionNodeFound(); + else + throw new SelectionNodeFound(binding); +} +public String toString(int tab) { + String s = tabString(tab); + s += " class X { + * void foo() { + * + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.FieldReference; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReasons; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class SelectionOnFieldReference extends FieldReference { +public SelectionOnFieldReference(char[] source , long pos) { + super(source, pos); +} +public TypeBinding resolveType(BlockScope scope) { + super.resolveType(scope); + + // tolerate some error cases + if (binding == null || + !(binding.isValidBinding() || + binding.problemId() == ProblemReasons.NotVisible + || binding.problemId() == ProblemReasons.InheritedNameHidesEnclosingName + || binding.problemId() == ProblemReasons.NonStaticReferenceInConstructorInvocation + || binding.problemId() == ProblemReasons.NonStaticReferenceInStaticContext)) + throw new SelectionNodeFound(); + else + throw new SelectionNodeFound(binding); +} +public String toStringExpression(){ + return ""; //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnFieldType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnFieldType.java new file mode 100644 index 0000000..aaa85c6 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnFieldType.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; + +public class SelectionOnFieldType extends FieldDeclaration { + public SelectionOnFieldType(TypeReference type) { + super(); + this.sourceStart = type.sourceStart; + this.sourceEnd = type.sourceEnd; + this.type = type; + this.name = NoChar; + } + public String toString(int tab) { + return type.toString(tab); + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnImportReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnImportReference.java new file mode 100644 index 0000000..210eeb2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnImportReference.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Selection node build by the parser in any case it was intending to + * reduce an import reference containing the assist identifier. + * e.g. + * + * import java.[start]io[end].*; + * class X { + * void foo() { + * } + * } + * + * ---> + * class X { + * void foo() { + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; + +public class SelectionOnImportReference extends ImportReference { + +public SelectionOnImportReference(char[][] tokens , long[] positions) { + super(tokens, positions, false); +} +public String toString(int tab, boolean withOnDemand) { + + StringBuffer buffer = new StringBuffer(tabString(tab)); + buffer. append(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnLocalName.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnLocalName.java new file mode 100644 index 0000000..da3cc76 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnLocalName.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +import net.sourceforge.phpdt.internal.compiler.ast.Expression; +import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; + +public class SelectionOnLocalName extends LocalDeclaration{ + public SelectionOnLocalName(Expression expr, char[] name, int sourceStart, int sourceEnd) { + super(expr, name, sourceStart, sourceEnd); + } + + public void resolve(BlockScope scope) { + super.resolve(scope); + throw new SelectionNodeFound(binding); + } + + public String toString(int tab) { + String s = tabString(tab); + s += " class X { + * void foo() { + * + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.MessageSend; +import net.sourceforge.phpdt.internal.compiler.ast.ThisReference; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReasons; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class SelectionOnMessageSend extends MessageSend { + + public TypeBinding resolveType(BlockScope scope) { + super.resolveType(scope); + + // tolerate some error cases + if(binding == null || + !(binding.isValidBinding() || + binding.problemId() == ProblemReasons.NotVisible + || binding.problemId() == ProblemReasons.InheritedNameHidesEnclosingName + || binding.problemId() == ProblemReasons.NonStaticReferenceInConstructorInvocation + || binding.problemId() == ProblemReasons.NonStaticReferenceInStaticContext)) { + throw new SelectionNodeFound(); + } else { + throw new SelectionNodeFound(binding); + } + } + + public String toStringExpression() { + String s = ""; //$NON-NLS-1$ + return s; + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnPackageReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnPackageReference.java new file mode 100644 index 0000000..87a344b --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnPackageReference.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Selection node build by the parser in any case it was intending to + * reduce an package statement containing the assist identifier. + * e.g. + * + * package java.[start]io[end]; + * class X { + * void foo() { + * } + * } + * + * ---> + * class X { + * void foo() { + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; + +public class SelectionOnPackageReference extends ImportReference { +public SelectionOnPackageReference(char[][] tokens , long[] positions) { + super(tokens, positions, true); +} +public String toString(int tab, boolean withOnDemand) { + StringBuffer buffer = new StringBuffer(tabString(tab)); + buffer. append(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedAllocationExpression.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedAllocationExpression.java new file mode 100644 index 0000000..d679001 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedAllocationExpression.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Selection node build by the parser in any case it was intending to + * reduce an allocation expression containing the cursor. + * If the allocation expression is not qualified, the enclosingInstance field + * is null. + * e.g. + * + * class X { + * void foo() { + * new [start]Bar[end](1, 2) + * } + * } + * + * ---> class X { + * void foo() { + * + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.AnonymousLocalTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.QualifiedAllocationExpression; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReasons; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class SelectionOnQualifiedAllocationExpression extends QualifiedAllocationExpression { +public SelectionOnQualifiedAllocationExpression() { +} +public SelectionOnQualifiedAllocationExpression(AnonymousLocalTypeDeclaration anonymous) { + anonymousType = anonymous ; +} +public TypeBinding resolveType(BlockScope scope) { + super.resolveType(scope); + + // tolerate some error cases + if (binding == null || + !(binding.isValidBinding() || + binding.problemId() == ProblemReasons.NotVisible)) + throw new SelectionNodeFound(); + if (anonymousType == null) + throw new SelectionNodeFound(binding); + + // if selecting a type for an anonymous type creation, we have to + // find its target super constructor (if extending a class) or its target + // super interface (if extending an interface) + if (anonymousType.binding.superInterfaces == NoSuperInterfaces) { + // find the constructor binding inside the super constructor call + ConstructorDeclaration constructor = (ConstructorDeclaration) anonymousType.declarationOf(binding); + throw new SelectionNodeFound(constructor.constructorCall.binding); + } else { + // open on the only superinterface + throw new SelectionNodeFound(anonymousType.binding.superInterfaces[0]); + } +} +public String toStringExpression(int tab) { + return + ((this.enclosingInstance == null) ? + ""; //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedNameReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedNameReference.java new file mode 100644 index 0000000..3fd7a85 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedNameReference.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Selection node build by the parser in any case it was intending to + * reduce a qualified name reference containing the assist identifier. + * e.g. + * + * class X { + * Y y; + * void foo() { + * y.fred.[start]ba[end] + * } + * } + * + * ---> class X { + * Y y; + * void foo() { + * + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.QualifiedNameReference; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemFieldBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReasons; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReferenceBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class SelectionOnQualifiedNameReference extends QualifiedNameReference { + public long[] sourcePositions; // positions of each token, the last one being the positions of the completion identifier +public SelectionOnQualifiedNameReference(char[][] previousIdentifiers, char[] selectionIdentifier, long[] positions) { + super( + CharOperation.arrayConcat(previousIdentifiers, selectionIdentifier), + (int) (positions[0] >>> 32), + (int) positions[positions.length - 1]); + this.sourcePositions = positions; +} +public TypeBinding resolveType(BlockScope scope) { + // it can be a package, type, member type, local variable or field + binding = scope.getBinding(tokens, this); + if (!binding.isValidBinding()) { + if (binding instanceof ProblemFieldBinding) { + // tolerate some error cases + if (binding.problemId() == ProblemReasons.NotVisible + || binding.problemId() == ProblemReasons.InheritedNameHidesEnclosingName + || binding.problemId() == ProblemReasons.NonStaticReferenceInConstructorInvocation + || binding.problemId() == ProblemReasons.NonStaticReferenceInStaticContext) { + throw new SelectionNodeFound(binding); + } + scope.problemReporter().invalidField(this, (FieldBinding) binding); + } else if (binding instanceof ProblemReferenceBinding) { + // tolerate some error cases + if (binding.problemId() == ProblemReasons.NotVisible){ + throw new SelectionNodeFound(binding); + } + scope.problemReporter().invalidType(this, (TypeBinding) binding); + } else { + scope.problemReporter().unresolvableReference(this, binding); + } + throw new SelectionNodeFound(); + } + throw new SelectionNodeFound(binding); +} +public String toStringExpression() { + + StringBuffer buffer = new StringBuffer(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedSuperReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedSuperReference.java new file mode 100644 index 0000000..b6cfe20 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedSuperReference.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Selection node build by the parser in any case it was intending to + * reduce a qualified super reference containing the assist identifier. + * e.g. + * + * class X extends Z { + * class Y { + * void foo() { + * X.[start]super[end].bar(); + * } + * } + * } + * + * ---> class X { + * class Y { + * void foo() { + * + * } + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.QualifiedSuperReference; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class SelectionOnQualifiedSuperReference extends QualifiedSuperReference { +public SelectionOnQualifiedSuperReference(TypeReference name, int pos, int sourceEnd) { + super(name, pos, sourceEnd); +} +public TypeBinding resolveType(BlockScope scope) { + TypeBinding binding = super.resolveType(scope); + + if (binding == null || !binding.isValidBinding()) + throw new SelectionNodeFound(); + else + throw new SelectionNodeFound(binding); +} +public String toStringExpression(){ + + StringBuffer buffer = new StringBuffer(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedTypeReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedTypeReference.java new file mode 100644 index 0000000..5d49dfb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnQualifiedTypeReference.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Selection node build by the parser in any case it was intending to + * reduce a type reference containing the completion identifier as part + * of a qualified name. + * e.g. + * + * class X extends java.lang.[start]Object[end] + * + * ---> class X extends + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.QualifiedTypeReference; +import net.sourceforge.phpdt.internal.compiler.lookup.Binding; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReasons; +import net.sourceforge.phpdt.internal.compiler.lookup.Scope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class SelectionOnQualifiedTypeReference extends QualifiedTypeReference { +public SelectionOnQualifiedTypeReference(char[][] previousIdentifiers, char[] selectionIdentifier, long[] positions) { + super( + CharOperation.arrayConcat(previousIdentifiers, selectionIdentifier), + positions); +} +public void aboutToResolve(Scope scope) { + getTypeBinding(scope.parent); // step up from the ClassScope +} +public TypeBinding getTypeBinding(Scope scope) { + // it can be a package, type or member type + Binding binding = scope.getTypeOrPackage(tokens); + if (!binding.isValidBinding()) { + // tolerate some error cases + if (binding.problemId() == ProblemReasons.NotVisible){ + throw new SelectionNodeFound(binding); + } + scope.problemReporter().invalidType(this, (TypeBinding) binding); + throw new SelectionNodeFound(); + } + + throw new SelectionNodeFound(binding); +} +public String toStringExpression(int tab) { + + StringBuffer buffer = new StringBuffer(); + buffer.append(""); //$NON-NLS-1$ + return buffer.toString(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnSingleNameReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnSingleNameReference.java new file mode 100644 index 0000000..9589df2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnSingleNameReference.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Selection node build by the parser in any case it was intending to + * reduce a single name reference containing the assist identifier. + * e.g. + * + * class X { + * void foo() { + * [start]ba[end] + * } + * } + * + * ---> class X { + * void foo() { + * + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.SingleNameReference; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemFieldBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReasons; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReferenceBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class SelectionOnSingleNameReference extends SingleNameReference { +public SelectionOnSingleNameReference(char[] source, long pos) { + super(source, pos); +} +public TypeBinding resolveType(BlockScope scope) { + // it can be a package, type, member type, local variable or field + binding = scope.getBinding(token, VARIABLE | TYPE | PACKAGE, this); + if (!binding.isValidBinding()) { + if (binding instanceof ProblemFieldBinding) { + // tolerate some error cases + if (binding.problemId() == ProblemReasons.NotVisible + || binding.problemId() == ProblemReasons.InheritedNameHidesEnclosingName + || binding.problemId() == ProblemReasons.NonStaticReferenceInConstructorInvocation + || binding.problemId() == ProblemReasons.NonStaticReferenceInStaticContext){ + throw new SelectionNodeFound(binding); + } + scope.problemReporter().invalidField(this, (FieldBinding) binding); + } else if (binding instanceof ProblemReferenceBinding) { + // tolerate some error cases + if (binding.problemId() == ProblemReasons.NotVisible){ + throw new SelectionNodeFound(binding); + } + scope.problemReporter().invalidType(this, (TypeBinding) binding); + } else { + scope.problemReporter().unresolvableReference(this, binding); + } + throw new SelectionNodeFound(); + } + + throw new SelectionNodeFound(binding); +} +public String toStringExpression() { + return ""; //$NON-NLS-2$ //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnSingleTypeReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnSingleTypeReference.java new file mode 100644 index 0000000..7b4e42c --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnSingleTypeReference.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Selection node build by the parser in any case it was intending to + * reduce a type reference containing the selection identifier as a single + * name reference. + * e.g. + * + * class X extends [start]Object[end] + * + * ---> class X extends + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference; +import net.sourceforge.phpdt.internal.compiler.lookup.Binding; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReasons; +import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding; +import net.sourceforge.phpdt.internal.compiler.lookup.Scope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class SelectionOnSingleTypeReference extends SingleTypeReference { +public SelectionOnSingleTypeReference(char[] source, long pos) { + super(source, pos); +} +public void aboutToResolve(Scope scope) { + getTypeBinding(scope.parent); // step up from the ClassScope +} +public TypeBinding getTypeBinding(Scope scope) { + // it can be a package, type or member type + Binding binding = scope.getTypeOrPackage(new char[][] {token}); + if (!binding.isValidBinding()) { + scope.problemReporter().invalidType(this, (TypeBinding) binding); + throw new SelectionNodeFound(); + } + + throw new SelectionNodeFound(binding); +} +public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) { + super.resolveTypeEnclosing(scope, enclosingType); + + // tolerate some error cases + if (binding == null || + !(binding.isValidBinding() || + binding.problemId() == ProblemReasons.NotVisible)) + throw new SelectionNodeFound(); + else + throw new SelectionNodeFound(binding); +} +public String toStringExpression(int tab){ + + return "" ; //$NON-NLS-2$ //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnSuperReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnSuperReference.java new file mode 100644 index 0000000..13582bf --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnSuperReference.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Selection node build by the parser in any case it was intending to + * reduce a super reference containing the assist identifier. + * e.g. + * + * class X extends Z { + * class Y { + * void foo() { + * [start]super[end].bar(); + * } + * } + * } + * + * ---> class X { + * class Y { + * void foo() { + * + * } + * } + * } + * + */ + +import net.sourceforge.phpdt.internal.compiler.ast.SuperReference; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; + +public class SelectionOnSuperReference extends SuperReference { + +public SelectionOnSuperReference(int pos, int sourceEnd) { + super(pos, sourceEnd); +} +public TypeBinding resolveType(BlockScope scope) { + TypeBinding binding = super.resolveType(scope); + + if (binding == null || !binding.isValidBinding()) + throw new SelectionNodeFound(); + else + throw new SelectionNodeFound(binding); +} +public String toStringExpression(){ + + return ""; //$NON-NLS-2$ //$NON-NLS-1$ + +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionParser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionParser.java new file mode 100644 index 0000000..99f38b0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionParser.java @@ -0,0 +1,686 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Parser able to build specific completion parse nodes, given a cursorLocation. + * + * Cursor location denotes the position of the last character behind which completion + * got requested: + * -1 means completion at the very beginning of the source + * 0 means completion behind the first character + * n means completion behind the n-th character + */ + +import net.sourceforge.phpdt.internal.compiler.*; +import net.sourceforge.phpdt.internal.compiler.env.*; + +import net.sourceforge.phpdt.internal.codeassist.impl.*; +import net.sourceforge.phpdt.internal.compiler.ast.*; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; +import net.sourceforge.phpdt.internal.compiler.parser.*; +import net.sourceforge.phpdt.internal.compiler.problem.*; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +public class SelectionParser extends AssistParser { + + /* public fields */ + + public int selectionStart, selectionEnd; + + public static final char[] SUPER = "super".toCharArray(); //$NON-NLS-1$ + public static final char[] THIS = "this".toCharArray(); //$NON-NLS-1$ + +public SelectionParser(ProblemReporter problemReporter, boolean assertMode) { + super(problemReporter, assertMode); +} +public char[] assistIdentifier(){ + return ((SelectionScanner)scanner).selectionIdentifier; +} +protected void attachOrphanCompletionNode(){ + if (isOrphanCompletionNode){ + AstNode orphan = this.assistNode; + isOrphanCompletionNode = false; + + + /* if in context of a type, then persists the identifier into a fake field return type */ + if (currentElement instanceof RecoveredType){ + RecoveredType recoveredType = (RecoveredType)currentElement; + /* filter out cases where scanner is still inside type header */ + if (recoveredType.foundOpeningBrace) { + /* generate a pseudo field with a completion on type reference */ + if (orphan instanceof TypeReference){ + currentElement = currentElement.add(new SelectionOnFieldType((TypeReference)orphan), 0); + return; + } + } + } + + Statement statement = (Statement)wrapWithExplicitConstructorCallIfNeeded(orphan); + currentElement = currentElement.add(statement, 0); + currentToken = 0; // given we are not on an eof, we do not want side effects caused by looked-ahead token + } +} + +private boolean checkRecoveredType() { + if (currentElement instanceof RecoveredType){ + /* check if current awaiting identifier is the completion identifier */ + if (this.indexOfAssistIdentifier() < 0) return false; + + if ((lastErrorEndPosition >= selectionStart) + && (lastErrorEndPosition <= selectionEnd+1)){ + return false; + } + RecoveredType recoveredType = (RecoveredType)currentElement; + /* filter out cases where scanner is still inside type header */ + if (recoveredType.foundOpeningBrace) { + this.assistNode = this.getTypeReference(0); + this.lastCheckPoint = this.assistNode.sourceEnd + 1; + this.isOrphanCompletionNode = true; + return true; + } + } + return false; +} +protected void classInstanceCreation(boolean alwaysQualified) { + + // ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt + + // ClassBodyopt produces a null item on the astStak if it produces NO class body + // An empty class body produces a 0 on the length stack..... + + int length; + if (((length = astLengthStack[astLengthPtr]) == 1) + && (astStack[astPtr] == null)) { + + if (this.indexOfAssistIdentifier() < 0) { + super.classInstanceCreation(alwaysQualified); + return; + } + QualifiedAllocationExpression alloc; + astPtr--; + astLengthPtr--; + alloc = new SelectionOnQualifiedAllocationExpression(); + alloc.sourceEnd = endPosition; //the position has been stored explicitly + + if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) { + expressionPtr -= length; + System.arraycopy( + expressionStack, + expressionPtr + 1, + alloc.arguments = new Expression[length], + 0, + length); + } + // trick to avoid creating a selection on type reference + char [] oldIdent = this.assistIdentifier(); + this.setAssistIdentifier(null); + alloc.type = getTypeReference(0); + this.setAssistIdentifier(oldIdent); + + //the default constructor with the correct number of argument + //will be created and added by the TC (see createsInternalConstructorWithBinding) + alloc.sourceStart = intStack[intPtr--]; + pushOnExpressionStack(alloc); + + this.assistNode = alloc; + this.lastCheckPoint = alloc.sourceEnd + 1; + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + this.isOrphanCompletionNode = true; + } else { + super.classInstanceCreation(alwaysQualified); + } +} + +protected void consumeArrayCreationExpression() { + // ArrayCreationExpression ::= 'new' PrimitiveType DimWithOrWithOutExprs ArrayInitializeropt + // ArrayCreationExpression ::= 'new' ClassOrInterfaceType DimWithOrWithOutExprs ArrayInitializeropt + + super.consumeArrayCreationExpression(); + + ArrayAllocationExpression alloc = (ArrayAllocationExpression)expressionStack[expressionPtr]; + if (alloc.type == assistNode){ + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + this.isOrphanCompletionNode = true; + } +} +protected void consumeEnterAnonymousClassBody() { + // EnterAnonymousClassBody ::= $empty + + if (this.indexOfAssistIdentifier() < 0) { + super.consumeEnterAnonymousClassBody(); + return; + } + QualifiedAllocationExpression alloc; + AnonymousLocalTypeDeclaration anonymousType = + new AnonymousLocalTypeDeclaration(this.compilationUnit.compilationResult); + alloc = + anonymousType.allocation = new SelectionOnQualifiedAllocationExpression(anonymousType); + markCurrentMethodWithLocalType(); + pushOnAstStack(anonymousType); + + alloc.sourceEnd = rParenPos; //the position has been stored explicitly + int argumentLength; + if ((argumentLength = expressionLengthStack[expressionLengthPtr--]) != 0) { + expressionPtr -= argumentLength; + System.arraycopy( + expressionStack, + expressionPtr + 1, + alloc.arguments = new Expression[argumentLength], + 0, + argumentLength); + } + // trick to avoid creating a selection on type reference + char [] oldIdent = this.assistIdentifier(); + this.setAssistIdentifier(null); + alloc.type = getTypeReference(0); + this.setAssistIdentifier(oldIdent); + + anonymousType.sourceEnd = alloc.sourceEnd; + //position at the type while it impacts the anonymous declaration + anonymousType.sourceStart = anonymousType.declarationSourceStart = alloc.type.sourceStart; + alloc.sourceStart = intStack[intPtr--]; + pushOnExpressionStack(alloc); + + assistNode = alloc; + this.lastCheckPoint = alloc.sourceEnd + 1; + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + this.isOrphanCompletionNode = true; + + anonymousType.bodyStart = scanner.currentPosition; + listLength = 0; // will be updated when reading super-interfaces + // recovery + if (currentElement != null){ + lastCheckPoint = anonymousType.bodyStart; + currentElement = currentElement.add(anonymousType, 0); // the recoveryTokenCheck will deal with the open brace + lastIgnoredToken = -1; + } +} +protected void consumeEnterVariable() { + // EnterVariable ::= $empty + // do nothing by default + + super.consumeEnterVariable(); + + AbstractVariableDeclaration variable = (AbstractVariableDeclaration) astStack[astPtr]; + if (variable.type == assistNode){ + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + isOrphanCompletionNode = false; // already attached inside variable decl + } +} + +protected void consumeExitVariableWithInitialization() { + super.consumeExitVariableWithInitialization(); + + // does not keep the initialization if selection is not inside + AbstractVariableDeclaration variable = (AbstractVariableDeclaration) astStack[astPtr]; + int start = variable.initialization.sourceStart; + int end = variable.initialization.sourceEnd; + if ((selectionStart < start) && (selectionEnd < start) || + (selectionStart > end) && (selectionEnd > end)) { + variable.initialization = null; + } +} + +protected void consumeFieldAccess(boolean isSuperAccess) { + // FieldAccess ::= Primary '.' 'Identifier' + // FieldAccess ::= 'super' '.' 'Identifier' + + if (this.indexOfAssistIdentifier() < 0) { + super.consumeFieldAccess(isSuperAccess); + return; + } + FieldReference fieldReference = + new SelectionOnFieldReference( + identifierStack[identifierPtr], + identifierPositionStack[identifierPtr--]); + identifierLengthPtr--; + if (isSuperAccess) { //considerates the fieldReferenceerence beginning at the 'super' .... + fieldReference.sourceStart = intStack[intPtr--]; + fieldReference.receiver = new SuperReference(fieldReference.sourceStart, endPosition); + pushOnExpressionStack(fieldReference); + } else { //optimize push/pop + if ((fieldReference.receiver = expressionStack[expressionPtr]).isThis()) { //fieldReferenceerence begins at the this + fieldReference.sourceStart = fieldReference.receiver.sourceStart; + } + expressionStack[expressionPtr] = fieldReference; + } + assistNode = fieldReference; + this.lastCheckPoint = fieldReference.sourceEnd + 1; + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + this.isOrphanCompletionNode = true; +} +protected void consumeFormalParameter() { + if (this.indexOfAssistIdentifier() < 0) { + super.consumeFormalParameter(); + } else { + + identifierLengthPtr--; + char[] name = identifierStack[identifierPtr]; + long namePositions = identifierPositionStack[identifierPtr--]; + TypeReference type = getTypeReference(intStack[intPtr--] + intStack[intPtr--]); + intPtr -= 2; + Argument arg = + new SelectionOnArgumentName( + name, + namePositions, + type, + intStack[intPtr + 1] & ~AccDeprecated); // modifiers + pushOnAstStack(arg); + + assistNode = arg; + this.lastCheckPoint = (int) namePositions; + isOrphanCompletionNode = true; + + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + + /* if incomplete method header, listLength counter will not have been reset, + indicating that some arguments are available on the stack */ + listLength++; + } +} +protected void consumeInstanceOfExpression(int op) { + if (indexOfAssistIdentifier() < 0) { + super.consumeInstanceOfExpression(op); + } else { + getTypeReference(intStack[intPtr--]); + this.isOrphanCompletionNode = true; + this.restartRecovery = true; + this.lastIgnoredToken = -1; + } +} +protected void consumeMethodInvocationName() { + // MethodInvocation ::= Name '(' ArgumentListopt ')' + + // when the name is only an identifier...we have a message send to "this" (implicit) + + char[] selector = identifierStack[identifierPtr]; + int accessMode; + if(selector == this.assistIdentifier()) { + if(CharOperation.equals(selector, SUPER)) { + accessMode = ExplicitConstructorCall.Super; + } else if(CharOperation.equals(selector, THIS)) { + accessMode = ExplicitConstructorCall.This; + } else { + super.consumeMethodInvocationName(); + return; + } + } else { + super.consumeMethodInvocationName(); + return; + } + + final ExplicitConstructorCall constructorCall = new SelectionOnExplicitConstructorCall(accessMode); + constructorCall.sourceEnd = rParenPos; + constructorCall.sourceStart = (int) (identifierPositionStack[identifierPtr] >>> 32); + int length; + if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) { + expressionPtr -= length; + System.arraycopy(expressionStack, expressionPtr + 1, constructorCall.arguments = new Expression[length], 0, length); + } + + if (!diet){ + pushOnAstStack(constructorCall); + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } else { + pushOnExpressionStack(new Expression(){ + public TypeBinding resolveType(BlockScope scope) { + constructorCall.resolve(scope); + return null; + } + }); + } + this.assistNode = constructorCall; + this.lastCheckPoint = constructorCall.sourceEnd + 1; + this.isOrphanCompletionNode = true; +} +protected void consumeMethodInvocationPrimary() { + //optimize the push/pop + //MethodInvocation ::= Primary '.' 'Identifier' '(' ArgumentListopt ')' + + char[] selector = identifierStack[identifierPtr]; + int accessMode; + if(selector == this.assistIdentifier()) { + if(CharOperation.equals(selector, SUPER)) { + accessMode = ExplicitConstructorCall.Super; + } else if(CharOperation.equals(selector, THIS)) { + accessMode = ExplicitConstructorCall.This; + } else { + super.consumeMethodInvocationPrimary(); + return; + } + } else { + super.consumeMethodInvocationPrimary(); + return; + } + + final ExplicitConstructorCall constructorCall = new SelectionOnExplicitConstructorCall(accessMode); + constructorCall.sourceEnd = rParenPos; + int length; + if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) { + expressionPtr -= length; + System.arraycopy(expressionStack, expressionPtr + 1, constructorCall.arguments = new Expression[length], 0, length); + } + constructorCall.qualification = expressionStack[expressionPtr--]; + constructorCall.sourceStart = constructorCall.qualification.sourceStart; + + if (!diet){ + pushOnAstStack(constructorCall); + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } else { + pushOnExpressionStack(new Expression(){ + public TypeBinding resolveType(BlockScope scope) { + constructorCall.resolve(scope); + return null; + } + }); + } + + this.assistNode = constructorCall; + this.lastCheckPoint = constructorCall.sourceEnd + 1; + this.isOrphanCompletionNode = true; +} +protected void consumeTypeImportOnDemandDeclarationName() { + // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*' + /* push an ImportRef build from the last name + stored in the identifier stack. */ + + int index; + + /* no need to take action if not inside assist identifiers */ + if ((index = indexOfAssistIdentifier()) < 0) { + super.consumeTypeImportOnDemandDeclarationName(); + return; + } + /* retrieve identifiers subset and whole positions, the assist node positions + should include the entire replaced source. */ + int length = identifierLengthStack[identifierLengthPtr]; + char[][] subset = identifierSubSet(index+1); // include the assistIdentifier + identifierLengthPtr--; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + + /* build specific assist node on import statement */ + ImportReference reference = this.createAssistImportReference(subset, positions); + reference.onDemand = true; + assistNode = reference; + this.lastCheckPoint = reference.sourceEnd + 1; + + pushOnAstStack(reference); + + if (currentToken == TokenNameSEMICOLON){ + reference.declarationSourceEnd = scanner.currentPosition - 1; + } else { + reference.declarationSourceEnd = (int) positions[length-1]; + } + //endPosition is just before the ; + reference.declarationSourceStart = intStack[intPtr--]; + // flush annotations defined prior to import statements + reference.declarationSourceEnd = this.flushAnnotationsDefinedPriorTo(reference.declarationSourceEnd); + + // recovery + if (currentElement != null){ + lastCheckPoint = reference.declarationSourceEnd+1; + currentElement = currentElement.add(reference, 0); + lastIgnoredToken = -1; + restartRecovery = true; // used to avoid branching back into the regular automaton + } +} +public ImportReference createAssistImportReference(char[][] tokens, long[] positions){ + return new SelectionOnImportReference(tokens, positions); +} +public ImportReference createAssistPackageReference(char[][] tokens, long[] positions){ + return new SelectionOnPackageReference(tokens, positions); +} +protected LocalDeclaration createLocalDeclaration(Expression initialization,char[] name,int sourceStart,int sourceEnd) { + if (this.indexOfAssistIdentifier() < 0) { + return super.createLocalDeclaration(initialization, name, sourceStart, sourceEnd); + } else { + SelectionOnLocalName local = new SelectionOnLocalName(initialization, name, sourceStart, sourceEnd); + this.assistNode = local; + this.lastCheckPoint = sourceEnd + 1; + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + return local; + } +} +public NameReference createQualifiedAssistNameReference(char[][] previousIdentifiers, char[] name, long[] positions){ + return new SelectionOnQualifiedNameReference( + previousIdentifiers, + name, + positions); +} +public TypeReference createQualifiedAssistTypeReference(char[][] previousIdentifiers, char[] name, long[] positions){ + return new SelectionOnQualifiedTypeReference( + previousIdentifiers, + name, + positions); +} +public NameReference createSingleAssistNameReference(char[] name, long position) { + return new SelectionOnSingleNameReference(name, position); +} +public TypeReference createSingleAssistTypeReference(char[] name, long position) { + return new SelectionOnSingleTypeReference(name, position); +} +public CompilationUnitDeclaration dietParse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int selectionStart, int selectionEnd) { + + this.selectionStart = selectionStart; + this.selectionEnd = selectionEnd; + SelectionScanner selectionScanner = (SelectionScanner)this.scanner; + selectionScanner.selectionIdentifier = null; + selectionScanner.selectionStart = selectionStart; + selectionScanner.selectionEnd = selectionEnd; + return this.dietParse(sourceUnit, compilationResult); +} +protected NameReference getUnspecifiedReference() { + /* build a (unspecified) NameReference which may be qualified*/ + + int completionIndex; + + /* no need to take action if not inside completed identifiers */ + if ((completionIndex = indexOfAssistIdentifier()) < 0) { + return super.getUnspecifiedReference(); + } + + int length = identifierLengthStack[identifierLengthPtr]; + if (CharOperation.equals(assistIdentifier(), SUPER)){ + Reference reference; + if (completionIndex > 0){ // qualified super + // discard 'super' from identifier stacks + identifierLengthStack[identifierLengthPtr] = completionIndex; + int ptr = identifierPtr -= (length - completionIndex); + reference = + new SelectionOnQualifiedSuperReference( + getTypeReference(0), + (int)(identifierPositionStack[ptr+1] >>> 32), + (int) identifierPositionStack[ptr+1]); + } else { // standard super + identifierPtr -= length; + identifierLengthPtr--; + reference = new SelectionOnSuperReference((int)(identifierPositionStack[identifierPtr+1] >>> 32), (int) identifierPositionStack[identifierPtr+1]); + } + pushOnAstStack(reference); + this.assistNode = reference; + this.lastCheckPoint = reference.sourceEnd + 1; + if (!diet || dietInt != 0){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + this.isOrphanCompletionNode = true; + return new SingleNameReference(new char[0], 0); // dummy reference + } + NameReference nameReference; + /* retrieve identifiers subset and whole positions, the completion node positions + should include the entire replaced source. */ + char[][] subset = identifierSubSet(completionIndex); + identifierLengthPtr--; + identifierPtr -= length; + long[] positions = new long[length]; + System.arraycopy( + identifierPositionStack, + identifierPtr + 1, + positions, + 0, + length); + /* build specific completion on name reference */ + if (completionIndex == 0) { + /* completion inside first identifier */ + nameReference = this.createSingleAssistNameReference(assistIdentifier(), positions[0]); + } else { + /* completion inside subsequent identifier */ + nameReference = this.createQualifiedAssistNameReference(subset, assistIdentifier(), positions); + } + assistNode = nameReference; + this.lastCheckPoint = nameReference.sourceEnd + 1; + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + this.isOrphanCompletionNode = true; + return nameReference; +} +/* + * Copy of code from superclass with the following change: + * In the case of qualified name reference if the cursor location is on the + * qualified name reference, then create a CompletionOnQualifiedNameReference + * instead. + */ +protected NameReference getUnspecifiedReferenceOptimized() { + + int index = indexOfAssistIdentifier(); + NameReference reference = super.getUnspecifiedReferenceOptimized(); + + if (index >= 0){ + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + this.isOrphanCompletionNode = true; + } + return reference; +} +public void initializeScanner(){ + this.scanner = new SelectionScanner(this.assertMode); +} +protected MessageSend newMessageSend() { + // '(' ArgumentListopt ')' + // the arguments are on the expression stack + + char[] selector = identifierStack[identifierPtr]; + if (selector != this.assistIdentifier()){ + return super.newMessageSend(); + } + MessageSend messageSend = new SelectionOnMessageSend(); + int length; + if ((length = expressionLengthStack[expressionLengthPtr--]) != 0) { + expressionPtr -= length; + System.arraycopy( + expressionStack, + expressionPtr + 1, + messageSend.arguments = new Expression[length], + 0, + length); + }; + assistNode = messageSend; + if (!diet){ + this.restartRecovery = true; // force to restart in recovery mode + this.lastIgnoredToken = -1; + } + + this.isOrphanCompletionNode = true; + return messageSend; +} +public CompilationUnitDeclaration parse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int selectionStart, int selectionEnd) { + + this.selectionStart = selectionStart; + this.selectionEnd = selectionEnd; + SelectionScanner selectionScanner = (SelectionScanner)this.scanner; + selectionScanner.selectionIdentifier = null; + selectionScanner.selectionStart = selectionStart; + selectionScanner.selectionEnd = selectionEnd; + return this.parse(sourceUnit, compilationResult); +} +/* + * Reset context so as to resume to regular parse loop + * If unable to reset for resuming, answers false. + * + * Move checkpoint location, reset internal stacks and + * decide which grammar goal is activated. + */ +protected boolean resumeAfterRecovery() { + + /* if reached assist node inside method body, but still inside nested type, + should continue in diet mode until the end of the method body */ + if (this.assistNode != null + && !(referenceContext instanceof CompilationUnitDeclaration)){ + currentElement.preserveEnclosingBlocks(); + if (currentElement.enclosingType() == null){ + this.resetStacks(); + return false; + } + } + return super.resumeAfterRecovery(); +} + +public void selectionIdentifierCheck(){ + if (checkRecoveredType()) return; +} +public void setAssistIdentifier(char[] assistIdent){ + ((SelectionScanner)scanner).selectionIdentifier = assistIdent; +} +/* + * Update recovery state based on current parser/scanner state + */ +protected void updateRecoveryState() { + + /* expose parser state to recovery state */ + currentElement.updateFromParserState(); + + /* may be able to retrieve completionNode as an orphan, and then attach it */ + this.selectionIdentifierCheck(); + this.attachOrphanCompletionNode(); + + /* check and update recovered state based on current token, + this action is also performed when shifting token after recovery + got activated once. + */ + this.recoveryTokenCheck(); +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionScanner.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionScanner.java new file mode 100644 index 0000000..fafb5e7 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionScanner.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.codeassist.select; + +/* + * Scanner aware of a selection range. If finding an identifier which source range is exactly + * the same, then will record it so that the parser can make use of it. + * + * Source positions are zero-based and inclusive. + */ +import net.sourceforge.phpdt.core.compiler.InvalidInputException; +import net.sourceforge.phpdt.internal.compiler.parser.Scanner; + +public class SelectionScanner extends Scanner { + + public char[] selectionIdentifier; + public int selectionStart, selectionEnd; +/* + * Truncate the current identifier if it is containing the cursor location. Since completion is performed + * on an identifier prefix. + * + */ + +public SelectionScanner(boolean assertMode) { + super(false, false, false, assertMode); +} + +public char[] getCurrentIdentifierSource() { + + if (selectionIdentifier == null){ + if (selectionStart == startPosition && selectionEnd == currentPosition-1){ + if (withoutUnicodePtr != 0){ // check unicode scenario + System.arraycopy(withoutUnicodeBuffer, 1, selectionIdentifier = new char[withoutUnicodePtr], 0, withoutUnicodePtr); + } else { + int length = currentPosition - startPosition; + // no char[] sharing around completionIdentifier, we want it to be unique so as to use identity checks + System.arraycopy(source, startPosition, (selectionIdentifier = new char[length]), 0, length); + } + return selectionIdentifier; + } + } + return super.getCurrentIdentifierSource(); +} +/* + * In case we actually read a keyword which corresponds to the selected + * range, we pretend we read an identifier. + */ +public int scanIdentifierOrKeyword() throws InvalidInputException { + + int id = super.scanIdentifierOrKeyword(); + + // convert completed keyword into an identifier + if (id != TokenNameIdentifier + && startPosition == selectionStart + && currentPosition == selectionEnd+1){ + return TokenNameIdentifier; + } + return id; +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BasicCompilationUnit.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BasicCompilationUnit.java new file mode 100644 index 0000000..cbc4cbb --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BasicCompilationUnit.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.core; + +import java.io.File; +import java.io.IOException; + +import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit; +import net.sourceforge.phpdt.internal.compiler.util.Util; + +/** + * A basic implementation of ICompilationUnit + * for use in the SourceMapper. + * @see ICompilationUnit + */ +public class BasicCompilationUnit implements ICompilationUnit { + protected char[] contents; + protected char[] fileName; + protected char[][] packageName; + protected char[] mainTypeName; + protected String encoding; + +public BasicCompilationUnit(char[] contents, char[][] packageName, String fileName, String encoding) { + this.contents = contents; + this.fileName = fileName.toCharArray(); + this.packageName = packageName; + + int start = fileName.lastIndexOf("/") + 1; //$NON-NLS-1$ + if (start == 0 || start < fileName.lastIndexOf("\\")) //$NON-NLS-1$ + start = fileName.lastIndexOf("\\") + 1; //$NON-NLS-1$ + + int end = fileName.lastIndexOf("."); //$NON-NLS-1$ + if (end == -1) + end = fileName.length(); + + this.mainTypeName = fileName.substring(start, end).toCharArray(); + this.encoding = encoding; +} +public char[] getContents() { + if (this.contents != null) + return this.contents; // answer the cached source + + // otherwise retrieve it + try { + return Util.getFileCharContent(new File(new String(fileName)), this.encoding); + } catch (IOException e) { + } + return new char[0]; +} +public char[] getFileName() { + return this.fileName; +} +public char[] getMainTypeName() { + return this.mainTypeName; +} +public char[][] getPackageName() { + return this.packageName; +} +public String toString(){ + return "CompilationUnit: "+new String(fileName); //$NON-NLS-1$ +} +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java new file mode 100644 index 0000000..ef69dd2 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.core; + +import net.sourceforge.phpdt.core.IJavaElement; + +/** + * Holds cached structure and properties for a Java element. + * Subclassed to carry properties for specific kinds of elements. + */ +/* package */ class JavaElementInfo { + + /** + * Collection of handles of immediate children of this + * object. This is an empty array if this element has + * no children. + */ + protected IJavaElement[] fChildren; + + /** + * Shared empty collection used for efficiency. + */ + protected static IJavaElement[] fgEmptyChildren = new IJavaElement[]{}; + /** + * Is the structure of this element known + * @see IJavaElement#isStructureKnown() + */ + protected boolean fIsStructureKnown = false; + + /** + * Shared empty collection used for efficiency. + */ + static Object[] NO_NON_JAVA_RESOURCES = new Object[] {}; + protected JavaElementInfo() { + fChildren = fgEmptyChildren; + } + public void addChild(IJavaElement child) { + if (fChildren == fgEmptyChildren) { + setChildren(new IJavaElement[] {child}); + } else { + if (!includesChild(child)) { + setChildren(growAndAddToArray(fChildren, child)); + } + } + } + public Object clone() { + try { + return super.clone(); + } + catch (CloneNotSupportedException e) { + throw new Error(); + } + } + public IJavaElement[] getChildren() { + return fChildren; + } + /** + * Adds the new element to a new array that contains all of the elements of the old array. + * Returns the new array. + */ + protected IJavaElement[] growAndAddToArray(IJavaElement[] array, IJavaElement addition) { + IJavaElement[] old = array; + array = new IJavaElement[old.length + 1]; + System.arraycopy(old, 0, array, 0, old.length); + array[old.length] = addition; + return array; + } + /** + * Returns true if this child is in my children collection + */ + protected boolean includesChild(IJavaElement child) { + + for (int i= 0; i < fChildren.length; i++) { + if (fChildren[i].equals(child)) { + return true; + } + } + return false; + } + /** + * @see IJavaElement#isStructureKnown() + */ + public boolean isStructureKnown() { + return fIsStructureKnown; + } + /** + * Returns an array with all the same elements as the specified array except for + * the element to remove. Assumes that the deletion is contained in the array. + */ + protected IJavaElement[] removeAndShrinkArray(IJavaElement[] array, IJavaElement deletion) { + IJavaElement[] old = array; + array = new IJavaElement[old.length - 1]; + int j = 0; + for (int i = 0; i < old.length; i++) { + if (!old[i].equals(deletion)) { + array[j] = old[i]; + } else { + System.arraycopy(old, i + 1, array, j, old.length - (i + 1)); + return array; + } + j++; + } + return array; + } + public void removeChild(IJavaElement child) { + if (includesChild(child)) { + setChildren(removeAndShrinkArray(fChildren, child)); + } + } + public void setChildren(IJavaElement[] children) { + fChildren = children; + } + /** + * Sets whether the structure of this element known + * @see IJavaElement#isStructureKnown() + */ + public void setIsStructureKnown(boolean newIsStructureKnown) { + fIsStructureKnown = newIsStructureKnown; + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java new file mode 100644 index 0000000..3945211 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java @@ -0,0 +1,327 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.core; + +import org.eclipse.core.resources.IResourceStatus; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +import net.sourceforge.phpeclipse.PHPeclipsePlugin; +import net.sourceforge.phpdt.core.IJavaElement; +import net.sourceforge.phpdt.core.IJavaModelStatus; +import net.sourceforge.phpdt.core.IJavaModelStatusConstants; +//import net.sourceforge.phpdt.core.IPackageFragment; +//import net.sourceforge.phpdt.core.JavaCore; + +/** + * @see IJavaModelStatus + */ + +public class JavaModelStatus extends Status implements IJavaModelStatus, IJavaModelStatusConstants, IResourceStatus { + + /** + * The elements related to the failure, or null + * if no elements are involved. + */ + protected IJavaElement[] fElements = new IJavaElement[0]; + /** + * The path related to the failure, or null + * if no path is involved. + */ + protected IPath fPath; + /** + * The String related to the failure, or null + * if no String is involved. + */ + protected String fString; + /** + * Empty children + */ + protected final static IStatus[] fgEmptyChildren = new IStatus[] {}; + protected IStatus[] fChildren= fgEmptyChildren; + + /** + * Singleton OK object + */ + public static final IJavaModelStatus VERIFIED_OK = new JavaModelStatus(OK); + + /** + * Constructs an Java model status with no corresponding elements. + */ + public JavaModelStatus() { + // no code for an multi-status + super(ERROR, PHPeclipsePlugin.PLUGIN_ID, 0, "JavaModelStatus", null); //$NON-NLS-1$ + } + /** + * Constructs an Java model status with no corresponding elements. + */ + public JavaModelStatus(int code) { + super(ERROR, PHPeclipsePlugin.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$ + fElements= JavaElementInfo.fgEmptyChildren; + } +// /** +// * Constructs an Java model status with the given corresponding +// * elements. +// */ +// public JavaModelStatus(int code, IJavaElement[] elements) { +// super(ERROR, JavaCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$ +// fElements= elements; +// fPath= null; +// } + /** + * Constructs an Java model status with no corresponding elements. + */ +// public JavaModelStatus(int code, String string) { +// super(ERROR, JavaCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$ +// fElements= JavaElementInfo.fgEmptyChildren; +// fPath= null; +// fString = string; +// } +// /** +// * Constructs an Java model status with no corresponding elements. +// */ + public JavaModelStatus(int code, Throwable throwable) { + super(ERROR, PHPeclipsePlugin.PLUGIN_ID, code, "JavaModelStatus", throwable); //$NON-NLS-1$ + fElements= JavaElementInfo.fgEmptyChildren; + } +// /** +// * Constructs an Java model status with no corresponding elements. +// */ +// public JavaModelStatus(int code, IPath path) { +// super(ERROR, JavaCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$ +// fElements= JavaElementInfo.fgEmptyChildren; +// fPath= path; +// } + /** + * Constructs an Java model status with the given corresponding + * element. + */ +// public JavaModelStatus(int code, IJavaElement element) { +// this(code, new IJavaElement[]{element}); +// } +// /** +// * Constructs an Java model status with the given corresponding +// * element and string +// */ +// public JavaModelStatus(int code, IJavaElement element, String string) { +// this(code, new IJavaElement[]{element}); +// fString= string; +// } + /** + * Constructs an Java model status with no corresponding elements. + */ + public JavaModelStatus(CoreException coreException) { + super(ERROR, PHPeclipsePlugin.PLUGIN_ID, CORE_EXCEPTION, "JavaModelStatus", coreException); //$NON-NLS-1$ + fElements= JavaElementInfo.fgEmptyChildren; + } + protected int getBits() { + int severity = 1 << (getCode() % 100 / 33); + int category = 1 << ((getCode() / 100) + 3); + return severity | category; + } + /** + * @see IStatus + */ + public IStatus[] getChildren() { + return fChildren; + } + /** + * @see IJavaModelStatus + */ + public IJavaElement[] getElements() { + return fElements; + } + /** + * Returns the message that is relevant to the code of this status. + */ +// public String getMessage() { +// if (getException() == null) { +// switch (getCode()) { +// case CORE_EXCEPTION : +// return Util.bind("status.coreException"); //$NON-NLS-1$ +// case BUILDER_INITIALIZATION_ERROR: +// return Util.bind("build.initializationError"); //$NON-NLS-1$ +// case BUILDER_SERIALIZATION_ERROR: +// return Util.bind("build.serializationError"); //$NON-NLS-1$ +// case DEVICE_PATH: +// return Util.bind("status.cannotUseDeviceOnPath", getPath().toString()); //$NON-NLS-1$ +// case DOM_EXCEPTION: +// return Util.bind("status.JDOMError"); //$NON-NLS-1$ +// case ELEMENT_DOES_NOT_EXIST: +// return Util.bind("element.doesNotExist",fElements[0].getElementName()); //$NON-NLS-1$ +// case EVALUATION_ERROR: +// return Util.bind("status.evaluationError", getString()); //$NON-NLS-1$ +// case INDEX_OUT_OF_BOUNDS: +// return Util.bind("status.indexOutOfBounds"); //$NON-NLS-1$ +// case INVALID_CONTENTS: +// return Util.bind("status.invalidContents"); //$NON-NLS-1$ +// case INVALID_DESTINATION: +// return Util.bind("status.invalidDestination", fElements[0].getElementName()); //$NON-NLS-1$ +// case INVALID_ELEMENT_TYPES: +// StringBuffer buff= new StringBuffer(Util.bind("operation.notSupported")); //$NON-NLS-1$ +// for (int i= 0; i < fElements.length; i++) { +// if (i > 0) { +// buff.append(", "); //$NON-NLS-1$ +// } +// buff.append(fElements[0].getElementName()); +// } +// return buff.toString(); +// case INVALID_NAME: +// return Util.bind("status.invalidName", getString()); //$NON-NLS-1$ +// case INVALID_PACKAGE: +// return Util.bind("status.invalidPackage", getString()); //$NON-NLS-1$ +// case INVALID_PATH: +// return Util.bind("status.invalidPath", getPath() == null ? "null" : getPath().toString()); //$NON-NLS-1$ //$NON-NLS-2$ +// case INVALID_PROJECT: +// return Util.bind("status.invalidProject", getString()); //$NON-NLS-1$ +// case INVALID_RESOURCE: +// return Util.bind("status.invalidResource", getString()); //$NON-NLS-1$ +// case INVALID_RESOURCE_TYPE: +// return Util.bind("status.invalidResourceType", getString()); //$NON-NLS-1$ +// case INVALID_SIBLING: +// return Util.bind("status.invalidSibling", fElements[0].getElementName()); //$NON-NLS-1$ +// case IO_EXCEPTION: +// return Util.bind("status.IOException"); //$NON-NLS-1$ +// case NAME_COLLISION: +// if (fElements != null && fElements.length > 0) { +// IJavaElement element = fElements[0]; +// String name = element.getElementName(); +// if (element instanceof IPackageFragment && name.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) { +// return Util.bind("operation.cannotRenameDefaultPackage"); //$NON-NLS-1$ +// } +// } +// return Util.bind("status.nameCollision"); //$NON-NLS-1$ +// case NO_ELEMENTS_TO_PROCESS: +// return Util.bind("operation.needElements"); //$NON-NLS-1$ +// case NULL_NAME: +// return Util.bind("operation.needName"); //$NON-NLS-1$ +// case NULL_PATH: +// return Util.bind("operation.needPath"); //$NON-NLS-1$ +// case NULL_STRING: +// return Util.bind("operation.needString"); //$NON-NLS-1$ +// case PATH_OUTSIDE_PROJECT: +// return Util.bind("operation.pathOutsideProject", getString(), fElements[0].getElementName()); //$NON-NLS-1$ +// case READ_ONLY: +// IJavaElement element = fElements[0]; +// String name = element.getElementName(); +// if (element instanceof IPackageFragment && name.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) { +// return Util.bind("status.defaultPackageReadOnly"); //$NON-NLS-1$ +// } +// return Util.bind("status.readOnly", name); //$NON-NLS-1$ +// case RELATIVE_PATH: +// return Util.bind("operation.needAbsolutePath", getPath().toString()); //$NON-NLS-1$ +// case TARGET_EXCEPTION: +// return Util.bind("status.targetException"); //$NON-NLS-1$ +// case UPDATE_CONFLICT: +// return Util.bind("status.updateConflict"); //$NON-NLS-1$ +// case NO_LOCAL_CONTENTS : +// return Util.bind("status.noLocalContents", getPath().toString()); //$NON-NLS-1$ +// } +// return getString(); +// } else { +// return getException().getMessage(); +// } +// } + /** + * @see IJavaModelStatus#getPath() + */ + public IPath getPath() { + return fPath; + } + /** + * @see IStatus#getSeverity() + */ + public int getSeverity() { + if (fChildren == fgEmptyChildren) return super.getSeverity(); + int severity = -1; + for (int i = 0, max = fChildren.length; i < max; i++) { + int childrenSeverity = fChildren[i].getSeverity(); + if (childrenSeverity > severity) { + severity = childrenSeverity; + } + } + return severity; + } + /** + * @see IJavaModelStatus#getString() + */ + public String getString() { + return fString; + } + /** + * @see IJavaModelStatus#isDoesNotExist() + */ + public boolean isDoesNotExist() { + return getCode() == ELEMENT_DOES_NOT_EXIST; + } + /** + * @see IStatus#isMultiStatus() + */ + public boolean isMultiStatus() { + return fChildren != fgEmptyChildren; + } + /** + * @see IStatus#isOK() + */ + public boolean isOK() { + return getCode() == OK; + } + /** + * @see IStatus#matches(int) + */ + public boolean matches(int mask) { + if (! isMultiStatus()) { + return matches(this, mask); + } else { + for (int i = 0, max = fChildren.length; i < max; i++) { + if (matches((JavaModelStatus) fChildren[i], mask)) + return true; + } + return false; + } + } + /** + * Helper for matches(int). + */ + protected boolean matches(JavaModelStatus status, int mask) { + int severityMask = mask & 0x7; + int categoryMask = mask & ~0x7; + int bits = status.getBits(); + return ((severityMask == 0) || (bits & severityMask) != 0) && ((categoryMask == 0) || (bits & categoryMask) != 0); + } + /** + * Creates and returns a new IJavaModelStatus that is a + * a multi-status status. + * + * @see IStatus#isMultiStatus() + */ + public static IJavaModelStatus newMultiStatus(IJavaModelStatus[] children) { + JavaModelStatus jms = new JavaModelStatus(); + jms.fChildren = children; + return jms; + } + /** + * Returns a printable representation of this exception for debugging + * purposes. + */ + public String toString() { + if (this == VERIFIED_OK){ + return "JavaModelStatus[OK]"; //$NON-NLS-1$ + } + StringBuffer buffer = new StringBuffer(); + buffer.append("Java Model Status ["); //$NON-NLS-1$ + buffer.append(getMessage()); + buffer.append("]"); //$NON-NLS-1$ + return buffer.toString(); + } +} diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/TypeConverter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/TypeConverter.java new file mode 100644 index 0000000..dc7ef2a --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/TypeConverter.java @@ -0,0 +1,245 @@ +/******************************************************************************* + * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * IBM Corporation - initial API and implementation + ******************************************************************************/ +package net.sourceforge.phpdt.internal.core; + +import net.sourceforge.phpdt.core.IField; +import net.sourceforge.phpdt.core.IMethod; +import net.sourceforge.phpdt.core.IType; +import net.sourceforge.phpdt.core.JavaModelException; +import net.sourceforge.phpdt.core.Signature; +import net.sourceforge.phpdt.internal.compiler.CompilationResult; +import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.Argument; +import net.sourceforge.phpdt.internal.compiler.ast.ArrayQualifiedTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.ArrayTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.ImportReference; +import net.sourceforge.phpdt.internal.compiler.ast.MemberTypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.QualifiedTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference; +import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpdt.internal.compiler.ast.TypeReference; +import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpdt.internal.compiler.util.CharOperation; + +/** + * Converter from a type to an AST type declaration. + */ +public class TypeConverter { + + /** + * Convert a type into an AST type declaration and put it in the given compilation unit. + */ +// public static TypeDeclaration buildTypeDeclaration(IType type, CompilationUnitDeclaration compilationUnit, CompilationResult compilationResult, ProblemReporter problemReporter) throws JavaModelException { +// char[] packageName = type.getPackageFragment().getElementName().toCharArray(); +// +// if (packageName != null && packageName.length > 0) { +// compilationUnit.currentPackage = new ImportReference(CharOperation.splitOn('.', packageName), new long[]{0}, false); +// } +// +// /* convert type */ +// TypeDeclaration typeDeclaration = convert(type, null, null, compilationResult); +// +// IType alreadyComputedMember = type; +// IType parent = type.getDeclaringType(); +// TypeDeclaration previousDeclaration = typeDeclaration; +// while(parent != null) { +// TypeDeclaration declaration = convert(parent, alreadyComputedMember, (MemberTypeDeclaration)previousDeclaration, compilationResult); +// +// alreadyComputedMember = parent; +// previousDeclaration = declaration; +// parent = parent.getDeclaringType(); +// } +// +// compilationUnit.types = new TypeDeclaration[]{previousDeclaration}; +// +// return typeDeclaration; +// } + + private static FieldDeclaration convert(IField field, IType type) throws JavaModelException { + + FieldDeclaration fieldDeclaration = new FieldDeclaration(); + + fieldDeclaration.name = field.getElementName().toCharArray(); + fieldDeclaration.type = createTypeReference(Signature.toString(field.getTypeSignature()).toCharArray(), type); + fieldDeclaration.modifiers = field.getFlags(); + + return fieldDeclaration; + } + + private static AbstractMethodDeclaration convert(IMethod method, IType type, CompilationResult compilationResult) throws JavaModelException { + + AbstractMethodDeclaration methodDeclaration; + + if (method.isConstructor()) { + ConstructorDeclaration decl = new ConstructorDeclaration(compilationResult); + decl.isDefaultConstructor = false; + methodDeclaration = decl; + } else { + MethodDeclaration decl = new MethodDeclaration(compilationResult); + /* convert return type */ + decl.returnType = createTypeReference(Signature.toString(method.getReturnType()).toCharArray(), type); + methodDeclaration = decl; + } + methodDeclaration.selector = method.getElementName().toCharArray(); + methodDeclaration.modifiers = method.getFlags(); + + /* convert arguments */ + String[] argumentTypeNames = method.getParameterTypes(); + String[] argumentNames = method.getParameterNames(); + int argumentCount = argumentTypeNames == null ? 0 : argumentTypeNames.length; + methodDeclaration.arguments = new Argument[argumentCount]; + for (int i = 0; i < argumentCount; i++) { + methodDeclaration.arguments[i] = new Argument( + argumentNames[i].toCharArray(), + 0, + createTypeReference(Signature.toString(argumentTypeNames[i]).toCharArray(), type), + CompilerModifiers.AccDefault); + // do not care whether was final or not + } + + /* convert thrown exceptions */ + String[] exceptionTypeNames = method.getExceptionTypes(); + int exceptionCount = exceptionTypeNames == null ? 0 : exceptionTypeNames.length; + if(exceptionCount > 0) { + methodDeclaration.thrownExceptions = new TypeReference[exceptionCount]; + for (int i = 0; i < exceptionCount; i++) { + methodDeclaration.thrownExceptions[i] = + createTypeReference(Signature.toString(exceptionTypeNames[i]).toCharArray(), type); + } + } + return methodDeclaration; + } + + private static TypeDeclaration convert(IType type, IType alreadyComputedMember,MemberTypeDeclaration alreadyComputedMemberDeclaration, CompilationResult compilationResult) throws JavaModelException { + /* create type declaration - can be member type */ + TypeDeclaration typeDeclaration; + if (type.getDeclaringType() == null) { + typeDeclaration = new TypeDeclaration(compilationResult); + } else { + typeDeclaration = new MemberTypeDeclaration(compilationResult); + } + typeDeclaration.name = type.getElementName().toCharArray(); + typeDeclaration.modifiers = type.getFlags(); + + + /* set superclass and superinterfaces */ + if (type.getSuperclassName() != null) { + typeDeclaration.superclass = createTypeReference(type.getSuperclassName().toCharArray(), type); + } + String[] interfaceNames = type.getSuperInterfaceNames(); + int interfaceCount = interfaceNames == null ? 0 : interfaceNames.length; + typeDeclaration.superInterfaces = new TypeReference[interfaceCount]; + for (int i = 0; i < interfaceCount; i++) { + typeDeclaration.superInterfaces[i] = createTypeReference(interfaceNames[i].toCharArray(), type); + } + + /* convert member types */ + IType[] memberTypes = type.getTypes(); + int memberTypeCount = memberTypes == null ? 0 : memberTypes.length; + typeDeclaration.memberTypes = new MemberTypeDeclaration[memberTypeCount]; + for (int i = 0; i < memberTypeCount; i++) { + if(alreadyComputedMember != null && alreadyComputedMember.getFullyQualifiedName().equals(memberTypes[i].getFullyQualifiedName())) { + typeDeclaration.memberTypes[i] = alreadyComputedMemberDeclaration; + } else { + typeDeclaration.memberTypes[i] = + (MemberTypeDeclaration) convert(memberTypes[i], null, null, compilationResult); + } + } + + /* convert fields */ + IField[] fields = type.getFields(); + int fieldCount = fields == null ? 0 : fields.length; + typeDeclaration.fields = new FieldDeclaration[fieldCount]; + for (int i = 0; i < fieldCount; i++) { + typeDeclaration.fields[i] = convert(fields[i], type); + } + + /* convert methods - need to add default constructor if necessary */ + IMethod[] methods = type.getMethods(); + int methodCount = methods == null ? 0 : methods.length; + + /* source type has a constructor ? */ + /* by default, we assume that one is needed. */ + int neededCount = 1; + for (int i = 0; i < methodCount; i++) { + if (methods[i].isConstructor()) { + neededCount = 0; + // Does not need the extra constructor since one constructor already exists. + break; + } + } + typeDeclaration.methods = new AbstractMethodDeclaration[methodCount + neededCount]; + if (neededCount != 0) { // add default constructor in first position + typeDeclaration.methods[0] = typeDeclaration.createsInternalConstructor(false, false); + } + boolean isInterface = type.isInterface(); + for (int i = 0; i < methodCount; i++) { + AbstractMethodDeclaration method =convert(methods[i], type, compilationResult); + if (isInterface || method.isAbstract()) { // fix-up flag + method.modifiers |= CompilerModifiers.AccSemicolonBody; + } + typeDeclaration.methods[neededCount + i] = method; + } + return typeDeclaration; + } + + private static TypeReference createTypeReference(char[] type, IType contextType) { + try { + String[][] resolvedName = contextType.resolveType(new String(type)); + char[] superClassName = null; + if(resolvedName != null && resolvedName.length == 1) { + type= CharOperation.concat(resolvedName[0][0].toCharArray(), resolvedName[0][1].toCharArray(), '.'); + } + } catch (JavaModelException e) { + + } + + /* count identifiers and dimensions */ + int max = type.length; + int dimStart = max; + int dim = 0; + int identCount = 1; + for (int i = 0; i < max; i++) { + switch (type[i]) { + case '[' : + if (dim == 0) + dimStart = i; + dim++; + break; + case '.' : + identCount++; + break; + } + } + /* rebuild identifiers and dimensions */ + if (identCount == 1) { // simple type reference + if (dim == 0) { + return new SingleTypeReference(type, 0); + } else { + char[] identifier = new char[dimStart]; + System.arraycopy(type, 0, identifier, 0, dimStart); + return new ArrayTypeReference(identifier, dim, 0); + } + } else { // qualified type reference + char[][] identifiers = CharOperation.splitOn('.', type, 0, dimStart - 1); + if (dim == 0) { + return new QualifiedTypeReference(identifiers, new long[]{0}); + } else { + return new ArrayQualifiedTypeReference(identifiers, dim, new long[]{0}); + } + } + } +}