From 2e72ecbdb19911ca7e39e1b46632fd6e1bd20b94 Mon Sep 17 00:00:00 2001
From: khartlage
+ * For text insertions,
+ * For text removals,
+ * For replacements (including
+ * When a buffer is closed,
+ * This class is not intended to be instantiated or subclassed by clients.
+ * Instances of this class are automatically created by the Java model.
+ *
+ * Note that java model operations that manipulate an
+ * This interface may be implemented by clients.
+ *
+ * Has no effect if this buffer is read-only.
+ *
+ * A
+ * Has no effect if this buffer is read-only.
+ *
+ * A
+ * 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
+ * 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
+ * A
+ * A
+ * A
+ * A
+ * A
+ * The
+ * A
+ * Equivalent to
+ * Has no effect if this buffer is read-only.
+ *
+ * A
+ * Equivalent to
+ * Has no effect if this buffer is read-only.
+ *
+ * A
+ * This interface may be implemented by clients.
+ *
+ * This interface may be implemented by clients.
+ *
+ * This interface is not intended to be implemented by clients.
+ *
+ * This interface is not intended to be implemented by clients.
+ *
+ * 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 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,
+ * Optionally, the new type can be positioned before the specified
+ * sibling. If It is possible that a type with the same name already exists in this compilation unit.
+ * The value of the
+ * This interface may be implemented by clients.
+ *
+ * This interface is not intended to be implemented by clients.
+ *
+ * This interface is not intended to be implemented by clients.
+ *
+ * Methods annotated as "handle-only" do not require underlying elements to exist.
+ * Methods that require underlying elements to exist throw
+ * a
+ * This interface is not intended to be implemented by clients.
+ *
+ * For example, the corresponding resource for an
+ *
+ * @return the corresponding resource, or
+ * 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
+ * Note: This does not imply anything about consistency with the
+ * underlying resource/buffer contents.
+ *
+ * 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
+ *
+ * Optionally, each copy can positioned before a sibling
+ * element. If
+ * Optionally, each copy can be renamed. If
+ *
+ * Optionally, any existing child in the destination container with
+ * the same name can be replaced by specifying
+ * Optionally, each element can positioned before a sibling
+ * element. If
+ * Optionally, each element can be renamed. If
+ *
+ * Optionally, any existing child in the destination container with
+ * the same name can be replaced by specifying 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:
+ *
+ * Java model status object are distinguished by their plug-in id:
+ *
+ * A Java model status may also carry additional information (that is, in
+ * addition to the information defined in
+ * This interface is not intended to be implemented by clients.
+ *
+ * This interface declares constants only; it is not intended to be implemented
+ * or extended.
+ *
+ * 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 IBufferChangedListener
notifications.
+ * getOffset
is the offset
+ * of the first inserted character, getText
is the
+ * inserted text, and getLength
is 0.
+ * getOffset
is the offset
+ * of the first removed character, getText
is null
,
+ * and getLength
is the length of the text that was removed.
+ * 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.
+ * getOffset
is 0, getLength
+ * is 0, and getText
is null
.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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).
+ * 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.
+ * replace(0,getLength(),contents)
.
+ * 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.
+ * replace(0,getLength(),contents)
.
+ * 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.
+ * IBuffer
s for openables.
+ * 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.
+ * 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:
+ * 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.
+ * "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.
+ *
+ * CoreException
occurred while updating an underlying resource
+ * "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.
+ * CoreException
occurred while updating an underlying resource
+ * sibling
is null
, the type will be appended
+ * to the end of this compilation unit.
+ *
+ * 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
+ * true
- in this case the type is created with the new contentsfalse
- in this case a JavaModelException
is thrown 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
+ * CoreException
occurred while updating an underlying resource
+ * 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.
+ * 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.
+ * 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.
+ * JavaModelException
when an underlying element is missing.
+ * JavaModelException.isDoesNotExist
can be used to recognize
+ * this common special case.
+ * 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.
+ * 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.
+ * 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.
+ * 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.
+ * 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 IJavaProject
s.
+ * JavaCore.create(workspace.getRoot())
.
+ * null
is specified for a given sibling, the copy
+ * is inserted as the last child of its associated container.
+ * null
is specified for the new name, the copy
+ * is not renamed.
+ * true
for
+ * force. Otherwise an exception is thrown in the event that a name
+ * collision occurs.
+ * 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:
+ * CoreException
occurred while updating an underlying resource
+ * INVALID_DESTINATION
)
+ * INVALID_SIBLING
)
+ * INVALID_NAME
)
+ * replace
has been specified as false
(NAME_COLLISION
)
+ * READ_ONLY
)
+ *
+ *
+ */
+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.
+ * CoreException
occurred while updating an underlying resource
+ * READ_ONLY
)
+ * null
is specified for sibling, the element
+ * is inserted as the last child of its associated container.
+ * null
is specified for the new name, the element
+ * is not renamed.
+ * true
for
+ * force. Otherwise an exception is thrown in the event that a name
+ * collision occurs.
+ * 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 CoreException
occurred while updating an underlying resource
+ * INVALID_DESTINATION
)
+ * INVALID_SIBLING
)
+ * INVALID_NAME
)
+ * replace
has been specified as false
(NAME_COLLISION
)
+ * READ_ONLY
)
+ * 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:
+ *
+ *
+ *
+ *
+ *
+ * @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 CoreException
occurred while updating an underlying resource
+ * INVALID_NAME
)
+ * replace
has been specified as false
(NAME_COLLISION
)
+ * READ_ONLY
)
+ * JavaModelException
objects to indicate what went
+ * wrong.
+ * getPlugin
returns "net.sourceforge.phpdt.core"
.
+ * getCode
returns one of the status codes declared in
+ * IJavaModelStatusConstants
.
+ * IStatus
):
+ *
+ *
+ * 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.
+ * 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.
+ * .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.
+ *
+ * This interface is not intended to be implemented by clients. An instance
+ * of one of these handles can be created via
+ * JavaCore.create(project)
.
+ *
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:
+ *
ignoreUnresolvedVariable
was set to false
. 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:
+ *
ignoreUnresolvedVariable
was set to false
. 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: + *
PATH_OUTSIDE_PROJECT
)
+ * RELATIVE_PATH
)
+ * INVALID_PATH
)
+ * 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:
+ *
JavaConventions#validateClasspath
+ * 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:
+ *
CPE_PROJECT
refers to this project (INVALID_PATH)
+ * PATH_OUTSIDE_PROJECT
)
+ * RELATIVE_PATH
)
+ * INVALID_PATH
)
+ * 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, ornull
+ * 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:
+ *
"main"
void
static
and public
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:
+ *
true
if this element is open and:
+ * 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:
+ *
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:
+ *
+ * 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: + *
+ * 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 whethergetChildren
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 IJavaModelException
s. 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 += ""; //$NON-NLS-1$
+ return s;
+ }
+}
+
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnClassLiteralAccess.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnClassLiteralAccess.java
new file mode 100644
index 0000000..947c57f
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnClassLiteralAccess.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * 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 access to the literal 'class' containing the cursor.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * String[].[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 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 += ""; //$NON-NLS-1$
+ return s;
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnFieldName.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnFieldName.java
new file mode 100644
index 0000000..f5994ca
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnFieldName.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.FieldDeclaration;
+import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
+import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
+
+public class CompletionOnFieldName extends FieldDeclaration {
+ private static final char[] FAKENAMESUFFIX = " ".toCharArray(); //$NON-NLS-1$
+ public char[] realName;
+ public CompletionOnFieldName(Expression initialization, char[] name, int sourceStart, int sourceEnd) {
+ super(initialization, CharOperation.concat(name, FAKENAMESUFFIX), sourceStart, sourceEnd); //$NON-NLS-1$
+ this.realName = name;
+ }
+
+ public void resolve(MethodScope initializationScope) {
+ super.resolve(initializationScope);
+
+ throw new CompletionNodeFound(this, initializationScope);
+ }
+
+ public String toString(int tab) {
+ String s = tabString(tab);
+ s += ""; //$NON-NLS-1$
+ return s;
+ }
+}
+
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnFieldType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnFieldType.java
new file mode 100644
index 0000000..01bfd9b
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnFieldType.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.complete;
+
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce an type reference located as a potential return type for a class
+ * member, containing the cursor location.
+ * This node is only a fake-field wrapper of the actual completion node
+ * which is accessible as the fake-field type.
+ * e.g.
+ *
+ * class X {
+ * Obj[cursor]
+ * }
+ *
+ * ---> 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 += ""; //$NON-NLS-1$
+ return s;
+ }
+}
+
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMemberAccess.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMemberAccess.java
new file mode 100644
index 0000000..8933d7c
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMemberAccess.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.complete;
+
+/*
+ * Completion node build by the parser in any case it was intending to
+ * reduce an access to a member (field reference or message send)
+ * containing the completion identifier.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * bar().fred[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 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 += ""; //$NON-NLS-1$
+ return s;
+ }
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMethodReturnType.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMethodReturnType.java
new file mode 100644
index 0000000..a220457
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnMethodReturnType.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * 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.ast.TypeReference;
+import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
+
+public class CompletionOnMethodReturnType extends MethodDeclaration {
+ public CompletionOnMethodReturnType(TypeReference returnType, CompilationResult compilationResult){
+ super(compilationResult);
+ this.returnType = returnType;
+ this.sourceStart = returnType.sourceStart;
+ this.sourceEnd = returnType.sourceEnd;
+ }
+
+ public void resolveStatements(ClassScope upperScope) {
+ throw new CompletionNodeFound(this, upperScope);
+ }
+
+ public String toString(int tab) {
+ return returnType.toString(tab);
+ }
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnPackageReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnPackageReference.java
new file mode 100644
index 0000000..0bb48b2
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/complete/CompletionOnPackageReference.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * 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 package statement containing the cursor location.
+ * e.g.
+ *
+ * package 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 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 += ""; //$NON-NLS-1$
+ return s;
+ }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnExplicitConstructorCall.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnExplicitConstructorCall.java
new file mode 100644
index 0000000..6dc4365
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnExplicitConstructorCall.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * 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 explicit constructor call containing the cursor.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * Y.[start]super[end](1, 2)
+ * }
+ * }
+ *
+ * ---> 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 += ""; //$NON-NLS-1$
+ return s;
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnFieldReference.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnFieldReference.java
new file mode 100644
index 0000000..c5545c0
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnFieldReference.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 field reference containing the cursor.
+ * e.g.
+ *
+ * class X {
+ * void foo() {
+ * bar().[start]fred[end]
+ * }
+ * }
+ *
+ * ---> 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 += "";//$NON-NLS-1$
+ return s;
+ }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnMessageSend.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnMessageSend.java
new file mode 100644
index 0000000..70c5128
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/codeassist/select/SelectionOnMessageSend.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.select;
+
+/*
+ * Selection 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.[start]bar[end](1, 2)
+ * }
+ * }
+ *
+ * ---> 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});
+ }
+ }
+ }
+}
--
1.7.1