Bug 44141 - New formatter causes out of memory error
Summary: New formatter causes out of memory error
Status: RESOLVED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Text (show other bugs)
Version: 3.0   Edit
Hardware: PC Windows 2000
: P3 normal (vote)
Target Milestone: 3.0 M4   Edit
Assignee: Tom Hofmann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 61599 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-10-03 12:28 EDT by Philipe Mulet CLA
Modified: 2004-05-12 14:58 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Philipe Mulet CLA 2003-10-03 12:28:55 EDT
20030930+JDT patches

Attempting to format SearchEngine unit, I got out of memory errors, and 
following entries into the log:

!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:18:57.646
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns the number of bytes that can be read from this file input 
stream without blocking.
         * <p>Here is an example on how to use <code>availableSize</code>.</p>
         *
         * The Loop to compute the number of bytes works as follows:
         * <pre>
         * while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         * For further reference consult {@link org.eclipse.formatter}.
         * @param stream The file input stream to return the number of 
available bytes for.
         * @param size The current number of available bytes.
         * @return the number of bytes that can be read from this file input 
stream without blocking.
         * @exception IOException if an I/O error occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:18:57.677
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns the number of bytes that can be read from this file input 
stream
         * without blocking.
         * <p>
         * Here is an example on how to use <code>availableSize</code>.
         * </p>
         *
         * The Loop to compute the number of bytes works as follows:
         *
         * <pre>
while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         *
         * For further reference consult {@link org.eclipse.formatter}.
         *
         * @param stream
         *                     The file input stream to return the number of 
available bytes
         *                     for.
         * @param size
         *                     The current number of available bytes.
         * @return the number of bytes that can be read from this file input 
stream
         *                without blocking.
         * @exception IOException
         *                          if an I/O error occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:19:22.318
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns the number of bytes that can be read from this file input 
stream without blocking.
         * <p>Here is an example on how to use <code>availableSize</code>.</p>
         *
         * The Loop to compute the number of bytes works as follows:
         * <pre>
         * while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         * For further reference consult {@link org.eclipse.formatter}.
         * @param stream The file input stream to return the number of 
available bytes for.
         * @param size The current number of available bytes.
         * @return the number of bytes that can be read from this file input 
stream without blocking.
         * @exception IOException if an I/O error occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:19:22.349
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns the number of bytes that can be read from this file input 
stream
         * without blocking.
         * <p>
         * Here is an example on how to use <code>availableSize</code>.
         * </p>
         *
         * The Loop to compute the number of bytes works as follows:
         *
         * <pre>
while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         *
         * For further reference consult {@link org.eclipse.formatter}.
         *
         * @param stream
         *                     The file input stream to return the number of 
available bytes
         *                     for.
         * @param size
         *                     The current number of available bytes.
         * @return the number of bytes that can be read from this file input 
stream
         *                without blocking.
         * @exception IOException
         *                          if an I/O error occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:19:22.974
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns the number of bytes that can be read from this file input 
stream without blocking.
         * <p>Here is an example on how to use <code>availableSize</code>.</p>
         *
         * The Loop to compute the number of bytes works as follows:
         * <pre>
         * while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         * For further reference consult {@link org.eclipse.formatter}.
         * @param stream The file input stream to return the number of 
available bytes for.
         * @param size The current number of available bytes.
         * @return the number of bytes that can be read from this file input 
stream without blocking.
         * @exception IOException if an I/O error occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:19:22.990
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns the number of bytes that can be read from this file input 
stream
         * without blocking.
         * <p>
         * Here is an example on how to use <code>availableSize</code>.
         * </p>
         *
         * The Loop to compute the number of bytes works as follows:
         *
         * <pre>
while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         *
         * For further reference consult {@link org.eclipse.formatter}.
         *
         * @param stream
         *                     The file input stream to return the number of 
available bytes
         *                     for.
         * @param size
         *                     The current number of available bytes.
         * @return the number of bytes that can be read from this file input 
stream
         *                without blocking.
         * @exception IOException
         *                          if an I/O error occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:19:24.599
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns the number of bytes that can be read from this file input 
stream without blocking.
         * <p>Here is an example on how to use <code>availableSize</code>.</p>
         *
         * The Loop to compute the number of bytes works as follows:
         * <pre>
         * while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         * For further reference consult {@link org.eclipse.formatter}.
         * @param stream The file input stream to return the number of 
available bytes for.
         * @param size The current number of available bytes.
         * @return the number of bytes that can be read from this file input 
stream without blocking.
         * @exception IOException if an I/O error occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:19:24.646
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns
         * the
         * number
         * of
         * bytes
         * that
         * can
         * be
         * read
         * from
         * this
         * file
         * input
         * stream
         * without
         * blocking.
         * <p>
         * Here
         * is
         * an
         * example
         * on
         * how
         * to
         * use
         * <code>availableSize</code>.
         * </p>
         *
         * The
         * Loop
         * to
         * compute
         * the
         * number
         * of
         * bytes
         * works
         * as
         * follows:
         *
         * <pre>
while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         *
         * For
         * further
         * reference
         * consult
         * {@link org.eclipse.formatter}.
         *
         * @param
         * stream
         * The
         * file
         * input
         * stream
         * to
         * return
         * the
         * number
         * of
         * available
         * bytes
         * for.
         * @param
         * size
         * The
         * current
         * number
         * of
         * available
         * bytes.
         * @return
         * the
         * number
         * of
         * bytes
         * that
         * can
         * be
         * read
         * from
         * this
         * file
         * input
         * stream
         * without
         * blocking.
         * @exception
         * IOException
         * if
         * an
         * I/O
         * error
         * occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:19:25.177
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns the number of bytes that can be read from this file input 
stream without blocking.
         * <p>Here is an example on how to use <code>availableSize</code>.</p>
         *
         * The Loop to compute the number of bytes works as follows:
         * <pre>
         * while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         * For further reference consult {@link org.eclipse.formatter}.
         * @param stream The file input stream to return the number of 
available bytes for.
         * @param size The current number of available bytes.
         * @return the number of bytes that can be read from this file input 
stream without blocking.
         * @exception IOException if an I/O error occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:19:25.193
!MESSAGE formatter returned null-edit. 
string: /***********************************************************************
******
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *****************************************************************************/

package org.eclipse.formatter.example

/**
 * Example class showing the format of the new comment formatter
 * @version 1.0
 */
class File {

        /**
         * Returns the number of bytes that can be read from this file input 
stream without blocking.
         * <p>
         * Here is an example on how to use <code>availableSize</code>.
         * </p>
         *
         * The Loop to compute the number of bytes works as follows:
         *
         * <pre>
while ((size = availableSize(stream, size)) > 0) { System.out.println
("available"); }
         * </pre>
         *
         * For further reference consult {@link org.eclipse.formatter}.
         *
         * @param stream
         *                     The file input stream to return the number of 
available bytes for.
         * @param size
         *                     The current number of available bytes.
         * @return the number of bytes that can be read from this file input 
stream without blocking.
         * @exception IOException
         *                          if an I/O error occurs.
         */
        public static int availableSize(FileInputStream stream, int size) {

                if (size < currentSize) {
                try {
                size=(long)stream.available();
                } catch (IOException e) {

                }
                } else if (size == currentSize) {
                ++size;
                } else {
                --size;
                }
                return size;
        }
}
!ENTRY org.eclipse.ui 4 4 Oct 03, 2003 18:19:57.333
!MESSAGE Unhandled exception caught in event loop.
Unhandled exception caught in event loop.
Reason:
!ENTRY org.eclipse.ui 4 0 Oct 03, 2003 18:19:57.349
!MESSAGE java.lang.OutOfMemoryError
!STACK 0
java.lang.OutOfMemoryError
java.lang.OutOfMemoryError
java.lang.OutOfMemoryError
Comment 1 Olivier Thomann CLA 2003-10-03 12:34:39 EDT
After I fixed the source for the formatter page, I get these errors:
org.eclipse.jface.util.Assert$AssertionFailedException: Assertion failed: 
	at java.lang.Throwable.<init>(Throwable.java)
	at java.lang.Throwable.<init>(Throwable.java)
	at org.eclipse.jface.util.Assert$AssertionFailedException.<init>(Assert.java:54)
	at org.eclipse.jface.util.Assert.isTrue(Assert.java:168)
	at org.eclipse.jface.util.Assert.isTrue(Assert.java)
	at
org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.RangeDifferencer.findDifferences(RangeDifferencer.java)
	at
org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.RangeDifferencer.findRanges(RangeDifferencer.java:291)
	at
org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.RangeDifferencer.findRanges(RangeDifferencer.java:276)
	at
org.eclipse.ui.internal.texteditor.quickdiff.DocumentLineDiffer.handleChange(DocumentLineDiffer.java:773)
	at
org.eclipse.ui.internal.texteditor.quickdiff.DocumentLineDiffer$1.run(DocumentLineDiffer.java:575)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:61)


and:
org.eclipse.jface.util.Assert$AssertionFailedException: Assertion failed: 
	at java.lang.Throwable.<init>(Throwable.java)
	at java.lang.Throwable.<init>(Throwable.java)
	at org.eclipse.jface.util.Assert$AssertionFailedException.<init>(Assert.java:54)
	at org.eclipse.jface.util.Assert.isTrue(Assert.java:168)
	at org.eclipse.jface.util.Assert.isTrue(Assert.java)
	at
org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.RangeDifferencer.findDifferences(RangeDifferencer.java)
	at
org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.RangeDifferencer.findRanges(RangeDifferencer.java:291)
	at
org.eclipse.ui.internal.texteditor.quickdiff.compare.rangedifferencer.RangeDifferencer.findRanges(RangeDifferencer.java:276)
	at
org.eclipse.ui.internal.texteditor.quickdiff.DocumentLineDiffer.handleChange(DocumentLineDiffer.java:773)
	at
org.eclipse.ui.internal.texteditor.quickdiff.DocumentLineDiffer.documentChanged(DocumentLineDiffer.java:655)
	at
org.eclipse.jface.text.AbstractDocument.doFireDocumentChanged2(AbstractDocument.java)
	at
org.eclipse.jface.text.AbstractDocument.doFireDocumentChanged(AbstractDocument.java)
	at
org.eclipse.jface.text.AbstractDocument.doFireDocumentChanged(AbstractDocument.java)
	at
org.eclipse.jface.text.AbstractDocument.fireDocumentChanged(AbstractDocument.java)
	at org.eclipse.jface.text.AbstractDocument.replace(AbstractDocument.java)
	at
org.eclipse.jdt.internal.ui.javaeditor.PartiallySynchronizedDocument.replace(PartiallySynchronizedDocument.java:61)
	at
org.eclipse.jdt.internal.ui.text.comment.CommentRegion.applyText(CommentRegion.java)
	at
org.eclipse.jdt.internal.ui.text.comment.CommentLine.applyLine(CommentLine.java:125)
	at
org.eclipse.jdt.internal.ui.text.comment.CommentRegion.applyRegion(CommentRegion.java:167)
	at
org.eclipse.jdt.internal.ui.text.comment.CommentRegion.format(CommentRegion.java:256)
	at
org.eclipse.jdt.internal.ui.text.comment.CommentFormattingStrategy.format(CommentFormattingStrategy.java:131)
	at
org.eclipse.jface.text.formatter.ContentFormatter.format(ContentFormatter.java:782)
	at
org.eclipse.jface.text.formatter.ContentFormatter.formatPartitions(ContentFormatter.java:602)
	at
org.eclipse.jface.text.formatter.ContentFormatter.format(ContentFormatter.java:491)
	at org.eclipse.jface.text.source.SourceViewer.doOperation(SourceViewer.java:664)
	at
org.eclipse.jdt.internal.ui.javaeditor.JavaSourceViewer.doOperation(JavaSourceViewer.java:98)
	at
org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor$AdaptedSourceViewer.doOperation(CompilationUnitEditor.java:169)
	at
org.eclipse.ui.texteditor.TextOperationAction$1.run(TextOperationAction.java:122)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java)
	at org.eclipse.ui.texteditor.TextOperationAction.run(TextOperationAction.java:120)
	at org.eclipse.jface.action.Action.runWithEvent(Action.java:842)
	at
org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:543)
	at
org.eclipse.jface.action.ActionContributionItem.access$4(ActionContributionItem.java:496)
	at
org.eclipse.jface.action.ActionContributionItem$6.handleEvent(ActionContributionItem.java:468)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2106)
	at org.eclipse.ui.internal.Workbench.run(Workbench.java:2089)
	at
org.eclipse.core.internal.boot.InternalBootLoader.run(InternalBootLoader.java:858)
	at org.eclipse.core.boot.BootLoader.run(BootLoader.java:461)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:79)
	at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:41)
	at java.lang.reflect.Method.invoke(Method.java:386)
	at org.eclipse.core.launcher.Main.basicRun(Main.java:298)
	at org.eclipse.core.launcher.Main.run(Main.java:764)
	at org.eclipse.core.launcher.Main.main(Main.java:598)
Comment 2 Olivier Thomann CLA 2003-10-03 12:49:27 EDT
Formatted ouput is with line split = 120. I don't see what I could do to fix it.

/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.core.search;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.AbstractSyntaxTreeVisitorAdapter;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.ast.AnonymousLocalTypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.LocalTypeDeclaration;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.core.*;
import org.eclipse.jdt.internal.core.search.*;
import org.eclipse.jdt.internal.core.search.HierarchyScope;
import org.eclipse.jdt.internal.core.search.IndexSearchAdapter;
import org.eclipse.jdt.internal.core.search.IIndexSearchRequestor;
import org.eclipse.jdt.internal.core.search.IInfoConstants;
import org.eclipse.jdt.internal.core.search.JavaSearchScope;
import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
import org.eclipse.jdt.internal.core.search.PatternSearchJob;
import org.eclipse.jdt.internal.core.search.PathCollector;
import org.eclipse.jdt.internal.core.search.Util;
import org.eclipse.jdt.internal.core.search.indexing.*;
import org.eclipse.jdt.internal.core.search.matching.*;
import java.util.*;
/**
 * A <code>SearchEngine</code> searches for java elements following a search
pattern.
 * The search can be limited to a search scope.
 * <p>
 * Various search patterns can be created using the factory methods 
 * <code>createSearchPattern(String, int, int, boolean)</code>,
<code>createSearchPattern(IJavaElement, int)</code>,
 * <code>createOrSearchPattern(ISearchPattern, ISearchPattern)</code>.
 * </p>
 * <p>For example, one can search for references to a method in the hierarchy of
a type, 
 * or one can search for the declarations of types starting with "Abstract" in a
project.
 * </p>
 * <p>
 * This class may be instantiated; it is not intended to be subclassed.
 * </p>
 * TODO: remove IWorkspace argument on the search methods before 3.0
 */
public class SearchEngine {
    /*
     * A default parser to parse non-reconciled working copies
     */
    private Parser parser;
    private CompilerOptions compilerOptions;
    /*
     * A list of working copies that take precedence over their original 
     * compilation units.
     */
    private ICompilationUnit[] workingCopies;
    /*
     * A working copy owner whose working copies will take precedent over 
     * their original compilation units.
     */
    private WorkingCopyOwner workingCopyOwner;
    /**
     * For tracing purpose.
     */
    public static boolean VERBOSE = false;
    /**
     * Creates a new search engine.
     */
    public SearchEngine() {
        // will use working copies of PRIMARY owner
    }
    /**
     * Creates a new search engine with a list of working copies that will take
precedence over 
     * their original compilation units in the subsequent search operations.
     * <p>
     * Note that passing an empty working copy will be as if the original
compilation
     * unit had been deleted.</p>
     * <p>
     * Since 3.0 the given working copies take precedence over primary working
copies (if any).
     * 
     * @param workingCopies the working copies that take precedence over their
original compilation units
     * @since 2.0
     */
    public SearchEngine(IWorkingCopy[] workingCopies) {
        int length = workingCopies.length;
        System.arraycopy(workingCopies, 0, this.workingCopies = new
ICompilationUnit[length], 0, length);
    }
    /**
     * Creates a new search engine with the given working copy owner.
     * The working copies owned by this owner will take precedence over 
     * the primary compilation units in the subsequent search operations.
     * 
     * @param workingCopyOwner the owner of the working copies that take
precedence over their original compilation units
     * @since 3.0
     */
    public SearchEngine(WorkingCopyOwner workingCopyOwner) {
        this.workingCopyOwner = workingCopyOwner;
    }
    /**
     * Returns a java search scope limited to the hierarchy of the given type.
     * The java elements resulting from a search with this scope will
     * be types in this hierarchy, or members of the types in this hierarchy.
     *
     * @param type the focus of the hierarchy scope
     * @return a new hierarchy scope
     * @exception JavaModelException if the hierarchy could not be computed on
the given type
     */
    public static IJavaSearchScope createHierarchyScope(IType type) throws
JavaModelException {
        return createHierarchyScope(type, DefaultWorkingCopyOwner.PRIMARY);
    }
    /**
     * Returns a java search scope limited to the hierarchy of the given type.
     * When the hierarchy is computed, the types defined in the working copies owned
     * by the given owner take precedence over the original compilation units.
     * The java elements resulting from a search with this scope will
     * be types in this hierarchy, or members of the types in this hierarchy.
     *
     * @param type the focus of the hierarchy scope
     * @param the owner of working copies that take precedence over original
compilation units
     * @return a new hierarchy scope
     * @exception JavaModelException if the hierarchy could not be computed on
the given type
     * @since 3.0
     */
    public static IJavaSearchScope createHierarchyScope(IType type,
WorkingCopyOwner owner) throws JavaModelException {
        return new HierarchyScope(type, owner);
    }
    /**
     * Returns a java search scope limited to the given resources.
     * The java elements resulting from a search with this scope will
     * have their underlying resource included in or equals to one of the given
     * resources.
     * <p>
     * Resources must not overlap, for example, one cannot include a folder and
its children.
     * </p>
     *
     * @param resources the resources the scope is limited to
     * @return a new java search scope
     * @deprecated Use createJavaSearchScope(IJavaElement[]) instead
     */
    public static IJavaSearchScope createJavaSearchScope(IResource[] resources) {
        int length = resources.length;
        IJavaElement[] elements = new IJavaElement[length];
        for (int i = 0; i < length; i++) {
            elements[i] = JavaCore.create(resources[i]);
        }
        return createJavaSearchScope(elements);
    }
    /**
     * Returns a java search scope limited to the given java elements.
     * The java elements resulting from a search with this scope will
     * be children of the given elements.
     * <p>
     * If an element is an IJavaProject, then the project's source folders, 
     * its jars (external and internal) and its referenced projects (with their
source 
     * folders and jars, recursively) will be included.
     * If an element is an IPackageFragmentRoot, then only the package fragments of 
     * this package fragment root will be included.
     * If an element is an IPackageFragment, then only the compilation unit and
class 
     * files of this package fragment will be included. Subpackages will NOT be 
     * included.</p>
     * <p>
     * In other words, this is equivalent to using
SearchEngine.createJavaSearchScope(elements, true).</p>
     *
     * @param elements the java elements the scope is limited to
     * @return a new java search scope
     * @since 2.0
     */
    public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements) {
        return createJavaSearchScope(elements, true);
    }
    /**
     * Returns a java search scope limited to the given java elements.
     * The java elements resulting from a search with this scope will
     * be children of the given elements.
     * 
     * If an element is an IJavaProject, then the project's source folders, 
     * its jars (external and internal) and - if specified - its referenced
projects 
     * (with their source folders and jars, recursively) will be included.
     * If an element is an IPackageFragmentRoot, then only the package fragments of 
     * this package fragment root will be included.
     * If an element is an IPackageFragment, then only the compilation unit and
class 
     * files of this package fragment will be included. Subpackages will NOT be 
     * included.
     *
     * @param elements the java elements the scope is limited to
     * @param includeReferencedProjects a flag indicating if referenced projects
must be 
     * 									 recursively included
     * @return a new java search scope
     * @since 2.0
     */
    public static IJavaSearchScope createJavaSearchScope(IJavaElement[]
elements, boolean includeReferencedProjects) {
        JavaSearchScope scope = new JavaSearchScope();
        HashSet visitedProjects = new HashSet(2);
        for (int i = 0, length = elements.length; i < length; i++) {
            IJavaElement element = elements[i];
            if (element != null) {
                try {
                    if (element instanceof IJavaProject) {
                        scope.add((IJavaProject) element,
includeReferencedProjects, visitedProjects);
                    } else {
                        scope.add(element);
                    }
                } catch (JavaModelException e) {
                    // ignore
                }
            }
        }
        return scope;
    }
    /**
     * Returns a search pattern that combines the given two patterns into a "or"
pattern.
     * The search result will match either the left pattern or the right pattern.
     *
     * @param leftPattern the left pattern
     * @param rightPattern the right pattern
     * @return a "or" pattern
     */
    public static ISearchPattern createOrSearchPattern(ISearchPattern
leftPattern, ISearchPattern rightPattern) {
        return new OrPattern((SearchPattern) leftPattern, (SearchPattern)
rightPattern);
    }
    /**
     * Returns a search pattern based on a given string pattern. The string
patterns support '*' wild-cards.
     * The remaining parameters are used to narrow down the type of expected
results.
     *
     * <br>
     *	Examples:
     *	<ul>
     * 		<li>search for case insensitive references to <code>Object</code>:
     *			<code>createSearchPattern("Object", TYPE, REFERENCES, false);</code></li>
     *  	<li>search for case sensitive references to exact <code>Object()</code>
constructor:
     *			<code>createSearchPattern("java.lang.Object()", CONSTRUCTOR,
REFERENCES, true);</code></li>
     *  	<li>search for implementers of <code>java.lang.Runnable</code>:
     *			<code>createSearchPattern("java.lang.Runnable", TYPE, IMPLEMENTORS,
true);</code></li>
     *  </ul>
     * @param stringPattern the given pattern
     * @param searchFor determines the nature of the searched elements
     *	<ul>
     * 		<li><code>IJavaSearchConstants.CLASS</code>: only look for classes</li>
     *		<li><code>IJavaSearchConstants.INTERFACE</code>: only look for
interfaces</li>
     * 		<li><code>IJavaSearchConstants.TYPE</code>: look for both classes and
interfaces</li>
     *		<li><code>IJavaSearchConstants.FIELD</code>: look for fields</li>
     *		<li><code>IJavaSearchConstants.METHOD</code>: look for methods</li>
     *		<li><code>IJavaSearchConstants.CONSTRUCTOR</code>: look for
constructors</li>
     *		<li><code>IJavaSearchConstants.PACKAGE</code>: look for packages</li>
     *	</ul>
     * @param limitTo determines the nature of the expected matches
     *	<ul>
     * 		<li><code>IJavaSearchConstants.DECLARATIONS</code>: will search
declarations matching with the corresponding
     * 			element. In case the element is a method, declarations of matching
methods in subtypes will also
     *  		be found, allowing to find declarations of abstract methods, etc.</li>
     *
     *		 <li><code>IJavaSearchConstants.REFERENCES</code>: will search
references to the given element.</li>
     *
     *		 <li><code>IJavaSearchConstants.ALL_OCCURRENCES</code>: will search for
either declarations or references as specified
     *  		above.</li>
     *
     *		 <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: for interface, will
find all types which implements a given interface.</li>
     *	</ul>
     *
     * @param isCaseSensitive indicates whether the search is case sensitive or not.
     * @return a search pattern on the given string pattern, or
<code>null</code> if the string pattern is ill-formed.
     */
    public static ISearchPattern createSearchPattern(String stringPattern, int
searchFor, int limitTo,
            boolean isCaseSensitive) {
        int matchMode;
        if (stringPattern.indexOf('*') != -1 || stringPattern.indexOf('?') != -1) {
            matchMode = IJavaSearchConstants.PATTERN_MATCH;
        } else {
            matchMode = IJavaSearchConstants.EXACT_MATCH;
        }
        return SearchPattern.createPattern(stringPattern, searchFor, limitTo,
matchMode, isCaseSensitive);
    }
    /**
     * Returns a search pattern based on a given Java element. 
     * The pattern is used to trigger the appropriate search, and can be
parameterized as follows:
     *
     * @param element the java element the search pattern is based on
     * @param limitTo determines the nature of the expected matches
     * 	<ul>
     * 		<li><code>IJavaSearchConstants.DECLARATIONS</code>: will search
declarations matching with the corresponding
     * 			element. In case the element is a method, declarations of matching
methods in subtypes will also
     *  		be found, allowing to find declarations of abstract methods, etc.</li>
     *
     *		 <li><code>IJavaSearchConstants.REFERENCES</code>: will search
references to the given element.</li>
     *
     *		 <li><code>IJavaSearchConstants.ALL_OCCURRENCES</code>: will search for
either declarations or references as specified
     *  		above.</li>
     *
     *		 <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: for interface, will
find all types which implements a given interface.</li>
     *	</ul>
     * @return a search pattern for a java element or <code>null</code> if the
given element is ill-formed
     */
    public static ISearchPattern createSearchPattern(IJavaElement element, int
limitTo) {
        return SearchPattern.createPattern(element, limitTo);
    }
    /**
     * Returns a java search scope with the workspace as the only limit.
     *
     * @return a new workspace scope
     */
    public static IJavaSearchScope createWorkspaceScope() {
        return new JavaWorkspaceScope();
    }
    private Parser getParser() {
        if (this.parser == null) {
            this.compilerOptions = new CompilerOptions(JavaCore.getOptions());
            ProblemReporter problemReporter = new ProblemReporter(
                    DefaultErrorHandlingPolicies.proceedWithAllProblems(),
this.compilerOptions,
                    new DefaultProblemFactory());
            this.parser = new Parser(problemReporter, true);
        }
        return this.parser;
    }
    /**
     * Returns the underlying resource of the given element.
     */
    private IResource getResource(IJavaElement element) {
        if (element instanceof IMember) {
            ICompilationUnit cu = ((IMember) element).getCompilationUnit();
            if (cu != null) {
                return cu.getResource();
            }
        }
        return element.getResource();
    }
    /*
     * Returns the list of working copies used by this search engine.
     * Returns null if none.
     */
    private ICompilationUnit[] getWorkingCopies() {
        ICompilationUnit[] copies;
        if (this.workingCopies != null) {
            if (this.workingCopyOwner == null) {
                copies = JavaModelManager.getJavaModelManager()
                        .getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY,
false/*don't add primary WCs a second time*/);
                if (copies == null) {
                    copies = this.workingCopies;
                } else {
                    HashMap pathToCUs = new HashMap();
                    for (int i = 0, length = copies.length; i < length; i++) {
                        ICompilationUnit unit = copies[i];
                        pathToCUs.put(unit.getPath(), unit);
                    }
                    for (int i = 0, length = this.workingCopies.length; i <
length; i++) {
                        ICompilationUnit unit = this.workingCopies[i];
                        pathToCUs.put(unit.getPath(), unit);
                    }
                    int length = pathToCUs.size();
                    copies = new ICompilationUnit[length];
                    pathToCUs.values().toArray(copies);
                }
            } else {
                copies = this.workingCopies;
            }
        } else if (this.workingCopyOwner != null) {
            copies = JavaModelManager.getJavaModelManager()
                    .getWorkingCopies(this.workingCopyOwner, true/*add primary
WCs*/);
        } else {
            copies = JavaModelManager.getJavaModelManager()
                    .getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY,
false/*don't add primary WCs a second time*/);
        }
        if (copies == null)
            return null;
        // filter out primary working copies that are saved
        ICompilationUnit[] result = null;
        int length = copies.length;
        int index = 0;
        for (int i = 0; i < length; i++) {
            CompilationUnit copy = (CompilationUnit) copies[i];
            try {
                if (!copy.isPrimary() || copy.hasUnsavedChanges() ||
!copy.isBasedOn(copy.getResource())) {
                    if (result == null) {
                        result = new ICompilationUnit[length];
                    }
                    result[index++] = copy;
                }
            } catch (JavaModelException e) {
                // copy doesn't exist: ignore
            }
        }
        if (index != length && result != null) {
            System.arraycopy(result, 0, result = new ICompilationUnit[index], 0,
index);
        }
        return result;
    }
    /**
     * Returns the list of working copies used to do the search on the given
java element.
     */
    private ICompilationUnit[] getWorkingCopies(IJavaElement element) {
        if (element instanceof IMember) {
            ICompilationUnit cu = ((IMember) element).getCompilationUnit();
            if (cu != null && cu.isWorkingCopy()) {
                ICompilationUnit[] copies = getWorkingCopies();
                int length = copies == null ? 0 : copies.length;
                if (length > 0) {
                    ICompilationUnit[] newWorkingCopies = new
ICompilationUnit[length + 1];
                    System.arraycopy(copies, 0, newWorkingCopies, 0, length);
                    newWorkingCopies[length] = cu;
                    return newWorkingCopies;
                } else {
                    return new ICompilationUnit[]{cu};
                }
            }
        }
        return getWorkingCopies();
    }
    /**
     * Searches for the Java element determined by the given signature. The
signature
     * can be incomplete. For example, a call like 
     * <code>search(ws, "run()", METHOD,REFERENCES, col)</code>
     * searches for all references to the method <code>run</code>.
     *
     * Note that by default the pattern will be case insensitive. For specifying
case s
     * sensitive search, use <code>search(workspace,
createSearchPattern(patternString, searchFor, limitTo, true), scope,
resultCollector);</code>
     * 
     * @param workspace the workspace
     * @param pattern the pattern to be searched for
     * @param searchFor a hint what kind of Java element the string pattern
represents.
     *  Look into <code>IJavaSearchConstants</code> for valid values
     * @param limitTo one of the following values:
     *	<ul>
     *	  <li><code>IJavaSearchConstants.DECLARATIONS</code>: search 
     *		  for declarations only </li>
     *	  <li><code>IJavaSearchConstants.REFERENCES</code>: search 
     *		  for all references </li>
     *	  <li><code>IJavaSearchConstants.ALL_OCCURENCES</code>: search 
     *		  for both declarations and all references </li>
     *	  <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: search for
     *		  all implementors of an interface; the value is only valid if
     *		  the Java element represents an interface</li>
     * 	</ul>
     * @param scope the search result has to be limited to the given scope
     * @param resultCollector a callback object to which each match is reported	 
     * @exception JavaModelException if the search failed. Reasons include:
     *	<ul>
     *		<li>the classpath is incorrectly set</li>
     *	</ul>
     */
    public void search(IWorkspace workspace, String patternString, int
searchFor, int limitTo, IJavaSearchScope scope,
            IJavaSearchResultCollector resultCollector) throws JavaModelException {
        search(workspace, createSearchPattern(patternString, searchFor, limitTo,
true), scope, resultCollector);
    }
    /**
     * Searches for the given Java element.
     *
     * @param workspace the workspace
     * @param element the Java element to be searched for
     * @param limitTo one of the following values:
     *	<ul>
     *	  <li><code>IJavaSearchConstants.DECLARATIONS</code>: search 
     *		  for declarations only </li>
     *	  <li><code>IJavaSearchConstants.REFERENCES</code>: search 
     *		  for all references </li>
     *	  <li><code>IJavaSearchConstants.ALL_OCCURENCES</code>: search 
     *		  for both declarations and all references </li>
     *	  <li><code>IJavaSearchConstants.IMPLEMENTORS</code>: search for
     *		  all implementors of an interface; the value is only valid if
     *		  the Java element represents an interface</li>
     * 	</ul>
     * @param scope the search result has to be limited to the given scope
     * @param resultCollector a callback object to which each match is reported
     * @exception JavaModelException if the search failed. Reasons include:
     *	<ul>
     *		<li>the element doesn't exist</li>
     *		<li>the classpath is incorrectly set</li>
     *	</ul>
     */
    public void search(IWorkspace workspace, IJavaElement element, int limitTo,
IJavaSearchScope scope,
            IJavaSearchResultCollector resultCollector) throws JavaModelException {
        search(workspace, createSearchPattern(element, limitTo), scope,
resultCollector);
    }
    /**
     * Searches for matches of a given search pattern. Search patterns can be
created using helper
     * methods (from a String pattern or a Java element) and encapsulate the
description of what is
     * being searched (for example, search method declarations in a case
sensitive way).
     *
     * @param workspace the workspace
     * @param searchPattern the pattern to be searched for
     * @param scope the search result has to be limited to the given scope
     * @param resultCollector a callback object to which each match is reported
     * @exception JavaModelException if the search failed. Reasons include:
     *	<ul>
     *		<li>the classpath is incorrectly set</li>
     *	</ul>
     */
    public void search(IWorkspace workspace, ISearchPattern searchPattern,
IJavaSearchScope scope,
            IJavaSearchResultCollector resultCollector) throws JavaModelException {
        long start = -1;
        if (VERBOSE) {
            start = System.currentTimeMillis();
            System.out.println("Searching for " + searchPattern + " in " +
scope); //$NON-NLS-1$//$NON-NLS-2$
        }
        /* search is starting */
        resultCollector.aboutToStart();
        MatchLocator matchLocator = null;
        try {
            if (searchPattern == null)
                return;
            /* initialize progress monitor */
            IProgressMonitor progressMonitor = resultCollector.getProgressMonitor();
            if (progressMonitor != null) {
                progressMonitor.beginTask(Util.bind("engine.searching"), 100);
//$NON-NLS-1$
            }
            /* index search */
            PathCollector pathCollector = new PathCollector();
            // In the case of a hierarchy scope make sure that the hierarchy is
not computed.
            // MatchLocator will filter out elements not in the hierarchy
            SearchPattern pattern = (SearchPattern) searchPattern;
            if (scope instanceof HierarchyScope) {
                ((HierarchyScope) scope).needsRefresh = false;
                pattern.mustResolve = true; // force resolve to compute type
bindings
            }
            IndexManager indexManager =
JavaModelManager.getJavaModelManager().getIndexManager();
            int detailLevel = IInfoConstants.PathInfo | IInfoConstants.PositionInfo;
            matchLocator = new MatchLocator(pattern, detailLevel,
resultCollector, scope, progressMonitor == null
                    ? null
                    : new SubProgressMonitor(progressMonitor, 95));
            indexManager.performConcurrentJob(new PatternSearchJob(pattern,
scope, pattern.focus, pattern
                    .isPolymorphicSearch(), detailLevel,
                    pathCollector, indexManager),
IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
                    progressMonitor == null ? null : new
SubProgressMonitor(progressMonitor, 5));
            /* eliminating false matches and locating them */
            if (progressMonitor != null && progressMonitor.isCanceled())
                throw new OperationCanceledException();
            matchLocator.locateMatches(pathCollector.getPaths(), workspace,
workingCopiesThatCanSeeFocus(pattern.focus,
                    pattern.isPolymorphicSearch()));
            if (progressMonitor != null && progressMonitor.isCanceled())
                throw new OperationCanceledException();
            if (progressMonitor != null) {
                progressMonitor.done();
            }
            matchLocator.locatePackageDeclarations(workspace);
        } finally {
            /* search has ended */
            resultCollector.done();
            if (VERBOSE) {
                System.out.println("Total time: " + (System.currentTimeMillis()
- start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
                if (matchLocator != null)
                    System.out.println("Time in result collector: " +
matchLocator.resultCollectorTime + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
            }
        }
    }
    /**
     * Searches for all top-level types and member types in the given scope.
     * The search can be selecting specific types (given a package or a type name
     * prefix and match modes). 
     * 
     * @param workspace the workspace to search in
     * @param packageName the full name of the package of the searched types, or
a prefix for this
     *						package, or a wild-carded string for this package.
     * @param typeName the dot-separated qualified name of the searched type
(the qualification include
     *					the enclosing types if the searched type is a member type), or a prefix
     *					for this type, or a wild-carded string for this type.
     * @param matchMode one of
     * <ul>
     *		<li><code>IJavaSearchConstants.EXACT_MATCH</code> if the package name
and type name are the full names
     *			of the searched types.</li>
     *		<li><code>IJavaSearchConstants.PREFIX_MATCH</code> if the package name
and type name are prefixes of the names
     *			of the searched types.</li>
     *		<li><code>IJavaSearchConstants.PATTERN_MATCH</code> if the package name
and type name contain wild-cards.</li>
     * </ul>
     * @param isCaseSensitive whether the search should be case sensitive
     * @param searchFor one of
     * <ul>
     * 		<li><code>IJavaSearchConstants.CLASS</code> if searching for classes
only</li>
     * 		<li><code>IJavaSearchConstants.INTERFACE</code> if searching for
interfaces only</li>
     * 		<li><code>IJavaSearchConstants.TYPE</code> if searching for both
classes and interfaces</li>
     * </ul>
     * @param scope the scope to search in
     * @param nameRequestor the requestor that collects the results of the search
     * @param waitingPolicy one of
     * <ul>
     *		<li><code>IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH</code> if the
search should start immediately</li>
     *		<li><code>IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH</code> if
the search should be cancelled if the
     *			underlying indexer has not finished indexing the workspace</li>
     *		<li><code>IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH</code> if the
search should wait for the
     *			underlying indexer to finish indexing the workspace</li>
     * </ul>
     * @param progressMonitor the progress monitor to report progress to, or
<code>null</code> if no progress
     *							monitor is provided
     * @exception JavaModelException if the search failed. Reasons include:
     *	<ul>
     *		<li>the classpath is incorrectly set</li>
     *	</ul>
     */
    public void searchAllTypeNames(IWorkspace workspace, char[] packageName,
char[] typeName, int matchMode,
            boolean isCaseSensitive, int searchFor, IJavaSearchScope scope,
final ITypeNameRequestor nameRequestor,
            int waitingPolicy, IProgressMonitor progressMonitor) throws
JavaModelException {
        IndexManager indexManager =
JavaModelManager.getJavaModelManager().getIndexManager();
        char classOrInterface;
        switch (searchFor) {
            case IJavaSearchConstants.CLASS :
                classOrInterface = IIndexConstants.CLASS_SUFFIX;
                break;
            case IJavaSearchConstants.INTERFACE :
                classOrInterface = IIndexConstants.INTERFACE_SUFFIX;
                break;
            default :
                classOrInterface = IIndexConstants.TYPE_SUFFIX;
                break;
        }
        SearchPattern pattern = new TypeDeclarationPattern(packageName, null, //
do find member types
                typeName, classOrInterface, matchMode, isCaseSensitive);
        final HashSet workingCopyPaths = new HashSet();
        ICompilationUnit[] copies = getWorkingCopies();
        if (copies != null) {
            for (int i = 0, length = copies.length; i < length; i++) {
                ICompilationUnit workingCopy = copies[i];
                workingCopyPaths.add(workingCopy.getPath().toString());
            }
        }
        IIndexSearchRequestor searchRequestor = new IndexSearchAdapter() {
            public void acceptClassDeclaration(String resourcePath, char[]
simpleTypeName, char[][] enclosingTypeNames,
                    char[] pkgName) {
                if (enclosingTypeNames != IIndexConstants.ONE_ZERO_CHAR //
filter out local and anonymous classes
                        && !workingCopyPaths.contains(resourcePath)) { // filter
out working copies
                    nameRequestor.acceptClass(pkgName, simpleTypeName,
enclosingTypeNames, resourcePath);
                }
            }
            public void acceptInterfaceDeclaration(String resourcePath, char[]
simpleTypeName,
                    char[][] enclosingTypeNames, char[] pkgName) {
                if (enclosingTypeNames != IIndexConstants.ONE_ZERO_CHAR //
filter out local and anonymous classes
                        && !workingCopyPaths.contains(resourcePath)) { // filter
out working copies
                    nameRequestor.acceptInterface(pkgName, simpleTypeName,
enclosingTypeNames, resourcePath);
                }
            }
        };
        try {
            if (progressMonitor != null) {
                progressMonitor.beginTask(Util.bind("engine.searching"), 100);
//$NON-NLS-1$
            }
            // add type names from indexes
            indexManager.performConcurrentJob(
			new PatternSearchJob(pattern, scope, IInfoConstants.NameInfo
                    | IInfoConstants.PathInfo, searchRequestor, indexManager),
                    waitingPolicy, progressMonitor == null ? null : new
SubProgressMonitor(progressMonitor, 100));
            // add type names from working copies
            if (copies != null) {
                for (int i = 0, length = copies.length; i < length; i++) {
                    ICompilationUnit workingCopy = copies[i];
                    IPackageDeclaration[] packageDeclarations =
workingCopy.getPackageDeclarations();
                    final String path = workingCopy.getPath().toString();
                    final char[] packageDeclaration = packageDeclarations.length
== 0
                            ? CharOperation.NO_CHAR
                            : packageDeclarations[0].getElementName().toCharArray();
                    if (workingCopy.isConsistent()) {
                        IType[] allTypes = workingCopy.getAllTypes();
                        for (int j = 0, allTypesLength = allTypes.length; j <
allTypesLength; j++) {
                            IType type = allTypes[j];
                            IJavaElement parent = type.getParent();
                            char[][] enclosingTypeNames;
                            if (parent instanceof IType) {
                                char[] parentQualifiedName = ((IType)
parent).getTypeQualifiedName('.').toCharArray();
                                enclosingTypeNames = CharOperation.splitOn('.',
parentQualifiedName);
                            } else {
                                enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
                            }
                            if (type.isClass()) {
                                nameRequestor.acceptClass(packageDeclaration,
type.getElementName().toCharArray(),
                                        enclosingTypeNames, path);
                            } else {
                               
nameRequestor.acceptInterface(packageDeclaration,
type.getElementName().toCharArray(),
                                        enclosingTypeNames, path);
                            }
                        }
                    } else {
                        Parser basicParser = getParser();
                        final char[] contents =
workingCopy.getBuffer().getCharacters();
                        org.eclipse.jdt.internal.compiler.env.ICompilationUnit
unit = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
                            public char[] getContents() {
                                return contents;
                            }
                            public char[] getMainTypeName() {
                                return null;
                            }
                            public char[][] getPackageName() {
                                return null;
                            }
                            public char[] getFileName() {
                                return null;
                            }
                        };
                        CompilationResult compilationUnitResult = new
CompilationResult(unit, 0, 0,
                                this.compilerOptions.maxProblemsPerUnit);
                        CompilationUnitDeclaration parsedUnit =
basicParser.dietParse(unit, compilationUnitResult);
                        if (parsedUnit != null) {
                            class AllTypeDeclarationsVisitor extends
AbstractSyntaxTreeVisitorAdapter {
                                public boolean visit(LocalTypeDeclaration
typeDeclaration, BlockScope blockScope) {
                                    return false; // no local type
                                }
                                public boolean
visit(AnonymousLocalTypeDeclaration typeDeclaration,
                                        BlockScope blockScope) {
                                    return false; // no anonymous type
                                }
                                public boolean visit(TypeDeclaration
typeDeclaration,
                                        CompilationUnitScope compilationUnitScope) {
                                    if (!typeDeclaration.isInterface()) {
                                       
nameRequestor.acceptClass(packageDeclaration, typeDeclaration.name,
                                                CharOperation.NO_CHAR_CHAR, path);
                                    } else {
                                       
nameRequestor.acceptInterface(packageDeclaration, typeDeclaration.name,
                                                CharOperation.NO_CHAR_CHAR, path);
                                    }
                                    return true;
                                }
                                public boolean visit(MemberTypeDeclaration
memberTypeDeclaration, ClassScope classScope) {
                                    // compute encloising type names
                                    TypeDeclaration enclosing =
memberTypeDeclaration.enclosingType;
                                    char[][] enclosingTypeNames =
CharOperation.NO_CHAR_CHAR;
                                    while (enclosing != null) {
                                        enclosingTypeNames =
CharOperation.arrayConcat(new char[][]{enclosing.name},
                                                enclosingTypeNames);
                                        if (enclosing instanceof
MemberTypeDeclaration) {
                                            enclosing = ((MemberTypeDeclaration)
enclosing).enclosingType;
                                        } else {
                                            enclosing = null;
                                        }
                                    }
                                    // report
                                    if (!memberTypeDeclaration.isInterface()) {
                                       
nameRequestor.acceptClass(packageDeclaration, memberTypeDeclaration.name,
                                                enclosingTypeNames, path);
                                    } else {
                                       
nameRequestor.acceptInterface(packageDeclaration, memberTypeDeclaration.name,
                                                enclosingTypeNames, path);
                                    }
                                    return true;
                                }
                            }
                            parsedUnit.traverse(new
AllTypeDeclarationsVisitor(), parsedUnit.scope);
                        }
                    }
                }
            }
        } finally {
            if (progressMonitor != null) {
                progressMonitor.done();
            }
        }
    }
    /**
     * Searches for all declarations of the fields accessed in the given element.
     * The element can be a compilation unit, a source type, or a source method.
     * Reports the field declarations using the given collector.
     * <p>
     * Consider the following code:
     * <code>
     * <pre>
     *		class A {
     *			int field1;
     *		}
     *		class B extends A {
     *			String value;
     *		}
     *		class X {
     *			void test() {
     *				B b = new B();
     *				System.out.println(b.value + b.field1);
     *			};
     *		}
     * </pre>
     * </code>
     * then searching for declarations of accessed fields in method 
     * <code>X.test()</code> would collect the fields
     * <code>B.value</code> and <code>A.field1</code>.
     * </p>
     *
     * @param workspace the workspace
     * @param enclosingElement the method, type, or compilation unit to be
searched in
     * @param resultCollector a callback object to which each match is reported
     * @exception JavaModelException if the search failed. Reasons include:
     *	<ul>
     *		<li>the element doesn't exist</li>
     *		<li>the classpath is incorrectly set</li>
     *	</ul>
     */
    public void searchDeclarationsOfAccessedFields(IWorkspace workspace,
IJavaElement enclosingElement,
            IJavaSearchResultCollector resultCollector) throws JavaModelException {
        SearchPattern pattern = new
DeclarationOfAccessedFieldsPattern(enclosingElement);
        IJavaSearchScope scope = createJavaSearchScope(new
IJavaElement[]{enclosingElement});
        IResource resource = this.getResource(enclosingElement);
        if (resource instanceof IFile) {
            if (VERBOSE) {
                System.out.println("Searching for " + pattern + " in " +
resource.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
            }
            MatchLocator locator = new MatchLocator(pattern,
IInfoConstants.DeclarationInfo, resultCollector, scope,
                    resultCollector.getProgressMonitor());
            locator.locateMatches(new
String[]{resource.getFullPath().toString()}, workspace, this.getWorkingCopies(
                    enclosingElement));
        } else {
            search(workspace, pattern, scope, resultCollector);
        }
    }
    /**
     * Searches for all declarations of the types referenced in the given element.
     * The element can be a compilation unit, a source type, or a source method.
     * Reports the type declarations using the given collector.
     * <p>
     * Consider the following code:
     * <code>
     * <pre>
     *		class A {
     *		}
     *		class B extends A {
     *		}
     *		interface I {
     *		  int VALUE = 0;
     *		}
     *		class X {
     *			void test() {
     *				B b = new B();
     *				this.foo(b, I.VALUE);
     *			};
     *		}
     * </pre>
     * </code>
     * then searching for declarations of referenced types in method
<code>X.test()</code>
     * would collect the class <code>B</code> and the interface <code>I</code>.
     * </p>
     *
     * @param workspace the workspace
     * @param enclosingElement the method, type, or compilation unit to be
searched in
     * @param resultCollector a callback object to which each match is reported
     * @exception JavaModelException if the search failed. Reasons include:
     *	<ul>
     *		<li>the element doesn't exist</li>
     *		<li>the classpath is incorrectly set</li>
     *	</ul>
     */
    public void searchDeclarationsOfReferencedTypes(IWorkspace workspace,
IJavaElement enclosingElement,
            IJavaSearchResultCollector resultCollector) throws JavaModelException {
        SearchPattern pattern = new
DeclarationOfReferencedTypesPattern(enclosingElement);
        IJavaSearchScope scope = createJavaSearchScope(new
IJavaElement[]{enclosingElement});
        IResource resource = this.getResource(enclosingElement);
        if (resource instanceof IFile) {
            if (VERBOSE) {
                System.out.println("Searching for " + pattern + " in " +
resource.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
            }
            MatchLocator locator = new MatchLocator(pattern,
IInfoConstants.DeclarationInfo, resultCollector, scope,
                    resultCollector.getProgressMonitor());
            locator.locateMatches(new
String[]{resource.getFullPath().toString()}, workspace, this.getWorkingCopies(
                    enclosingElement));
        } else {
            search(workspace, pattern, scope, resultCollector);
        }
    }
    /**
     * Searches for all declarations of the methods invoked in the given element.
     * The element can be a compilation unit, a source type, or a source method.
     * Reports the method declarations using the given collector.
     * <p>
     * Consider the following code:
     * <code>
     * <pre>
     *		class A {
     *			void foo() {};
     *			void bar() {};
     *		}
     *		class B extends A {
     *			void foo() {};
     *		}
     *		class X {
     *			void test() {
     *				A a = new B();
     *				a.foo();
     *				B b = (B)a;
     *				b.bar();
     *			};
     *		}
     * </pre>
     * </code>
     * then searching for declarations of sent messages in method 
     * <code>X.test()</code> would collect the methods
     * <code>A.foo()</code>, <code>B.foo()</code>, and <code>A.bar()</code>.
     * </p>
     *
     * @param workspace the workspace
     * @param enclosingElement the method, type, or compilation unit to be
searched in
     * @param resultCollector a callback object to which each match is reported
     * @exception JavaModelException if the search failed. Reasons include:
     *	<ul>
     *		<li>the element doesn't exist</li>
     *		<li>the classpath is incorrectly set</li>
     *	</ul>
     */
    public void searchDeclarationsOfSentMessages(IWorkspace workspace,
IJavaElement enclosingElement,
            IJavaSearchResultCollector resultCollector) throws JavaModelException {
        SearchPattern pattern = new
DeclarationOfReferencedMethodsPattern(enclosingElement);
        IJavaSearchScope scope = createJavaSearchScope(new
IJavaElement[]{enclosingElement});
        IResource resource = this.getResource(enclosingElement);
        if (resource instanceof IFile) {
            if (VERBOSE) {
                System.out.println("Searching for " + pattern + " in " +
resource.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
            }
            MatchLocator locator = new MatchLocator(pattern,
IInfoConstants.DeclarationInfo, resultCollector, scope,
                    resultCollector.getProgressMonitor());
            locator.locateMatches(new
String[]{resource.getFullPath().toString()}, workspace, this.getWorkingCopies(
                    enclosingElement));
        } else {
            search(workspace, pattern, scope, resultCollector);
        }
    }
    /*
     * Returns the working copies that cannot see the given focus.
     */
    private ICompilationUnit[] workingCopiesThatCanSeeFocus(IJavaElement focus,
boolean isPolymorphicSearch) {
        ICompilationUnit[] copies = getWorkingCopies();
        if (focus == null || copies == null)
            return copies;
        while (!(focus instanceof IJavaProject) && !(focus instanceof
JarPackageFragmentRoot)) {
            focus = focus.getParent();
        }
        int length = copies.length;
        ICompilationUnit[] result = null;
        int index = -1;
        for (int i = 0; i < length; i++) {
            ICompilationUnit workingCopy = copies[i];
            IPath projectOrJar =
IndexSelector.getProjectOrJar(workingCopy).getPath();
            if (!IndexSelector.canSeeFocus(focus, isPolymorphicSearch,
projectOrJar)) {
                if (result == null) {
                    result = new ICompilationUnit[length - 1];
                    System.arraycopy(copies, 0, result, 0, i);
                    index = i;
                }
            } else if (result != null) {
                result[index++] = workingCopy;
            }
        }
        if (result != null) {
            if (result.length != index) {
                System.arraycopy(result, 0, result = new
ICompilationUnit[index], 0, index);
            }
            return result;
        } else {
            return copies;
        }
    }
}
Comment 3 Philipe Mulet CLA 2003-10-03 12:53:09 EDT
I had enabled the new formatter (which generate edits)
Comment 4 Olivier Thomann CLA 2003-10-03 12:57:21 EDT
I could not reproduce the problem. I never get an OutOfMemory error.
Comment 5 Dani Megert CLA 2003-10-06 04:33:47 EDT
Java code formatter is Jdt Core. Comment formatting does not use edits and the
error message says:

!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:18:57.646
!MESSAGE formatter returned null-edit. 

Comment 6 Philipe Mulet CLA 2003-10-06 04:40:13 EDT
The null edits where a separate issue related to a bug in the formatter page. 
The suspicion is that the edit application is causing grief here. 

Comment 7 Dirk Baeumer CLA 2003-10-06 06:31:59 EDT
As discussed with Olivier the problem doesn't occur if the quick differences 
is disabled (see exception in comment #1). Moving to text for comments.
Comment 8 Dani Megert CLA 2003-10-06 06:49:04 EDT
To reproduce you have to enable the new formatter.
Comment 9 Martin Aeschlimann CLA 2003-10-06 07:03:34 EDT
The entry
'!ENTRY org.eclipse.jdt.ui 4 10001 Oct 03, 2003 18:18:57.646
!MESSAGE formatter returned null-edit.'
seen by Philippe came drom a bug in the codeformatter-example source.
This is fixed (different bug report)

BTW, Note that this is only a message in the log, not a stacktrace. It should
help us to find incompatibilities. If the new formatter returns a null edit
(source has syntax error or something else) I use the unformatted text.
I improve this warning message so it does not cause more confusion (will remove
the logging later when we're done with the conversion).
"formatter failed to format (no edit returned). Will use unformatted text
instead. kind: " + kind + ", string: " + string"









Comment 10 Tom Hofmann CLA 2003-10-06 09:45:29 EDT
There are at least two separate issues remaining: 

- The failed assertion in RangeDifferencer - the code is the same as everywhere
in compare and I cannot reproduce this - I assume it has to do with a concurrent
modification. 
-> I have a fix for this, although not a very satisfying one, which I will
commit shortly.

- The OutOfMemory error *can* and will happen when diffing large documents with
many changes. This is a shortcoming of the diff / alignment algorithm used,
which is O(number of changes^2) for space. The same will happen when
reformatting, say, StyledText and doing a compare with HEAD.

-> Workaround is to not use compare and disable quick diff (Ctrl+Shift+Q) in
such situations.
-> A long term solution would be to back off to a different diffing algo (Dan
Hirschberg's linear space algorithm for computing maximal common subsequences)
on large files.

Comment 11 Tom Hofmann CLA 2003-10-06 12:25:54 EDT
fixed the concurrency issue > 20031006

workaround for OutOfMemoryError described in comment 10.

Closing.
Comment 12 Olivier Thomann CLA 2004-05-12 14:58:49 EDT
*** Bug 61599 has been marked as a duplicate of this bug. ***