Bug 572236 - Very large memory usage by indexer

- don't use ThreadLocal for sourceIndexer
- cleanup reference of the sourceIndexer after use
- document sourceIndexer use (IndexManager.scheduleDocumentIndexing())

Change-Id: I3edc4be24eef31b89275e46ea038402e4ecbe118
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java
index fe29c40..149193a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchParticipant.java
@@ -36,7 +36,19 @@
 public class JavaSearchParticipant extends SearchParticipant implements IParallelizable {
 
 	private final ThreadLocal indexSelector = new ThreadLocal();
-	private final ThreadLocal<SourceIndexer> sourceIndexer = new ThreadLocal<SourceIndexer>();
+
+	/**
+	 * The only reason this field exist is the unfortunate idea to share created source indexer
+	 * between three calls to this search participant in IndexManager.scheduleDocumentIndexing().
+	 * <p>
+	 * The field is supposed to be set in indexDocument() and potentially reused
+	 * in later calls to resolveDocument() and indexResolvedDocument(), all in the same thread.
+	 * <p>
+	 * This is the only purpose of this field, and allows us not to manage it via ThreadLocal.
+	 * <p>
+	 * See org.eclipse.jdt.internal.core.search.indexing.IndexManager.scheduleDocumentIndexing()
+	 */
+	private SourceIndexer sourceIndexer;
 
 	@Override
 	public void beginSearching() {
@@ -68,8 +80,13 @@
 		String documentPath = document.getPath();
 		if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(documentPath)) {
 			SourceIndexer indexer = new SourceIndexer(document);
-			this.sourceIndexer.set(indexer);
 			indexer.indexDocument();
+
+			// if the indexer should index resolved document too, remember it for later
+			// See org.eclipse.jdt.internal.core.search.indexing.IndexManager.scheduleDocumentIndexing()
+			if(document.shouldIndexResolvedDocument()) {
+				this.sourceIndexer = indexer;
+			}
 		} else if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(documentPath)) {
 			new BinaryIndexer(document).indexDocument();
 		} else if (documentPath.endsWith(TypeConstants.AUTOMATIC_MODULE_NAME)) {
@@ -81,10 +98,13 @@
 	public void indexResolvedDocument(SearchDocument document, IPath indexPath) {
 		String documentPath = document.getPath();
 		if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(documentPath)) {
-			SourceIndexer indexer = this.sourceIndexer.get();
-			if (indexer != null)
+			SourceIndexer indexer = this.sourceIndexer;
+			if (indexer != null) {
 				indexer.indexResolvedDocument();
-			this.sourceIndexer.remove();
+				// Cleanup reference, it is not more needed by the IndexManager
+				// See org.eclipse.jdt.internal.core.search.indexing.IndexManager.scheduleDocumentIndexing()
+				this.sourceIndexer = null;
+			}
 		}
 	}
 
@@ -92,7 +112,7 @@
 	public void resolveDocument(SearchDocument document) {
 		String documentPath = document.getPath();
 		if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(documentPath)) {
-			SourceIndexer indexer = this.sourceIndexer.get();
+			SourceIndexer indexer = this.sourceIndexer;
 			if (indexer != null)
 				indexer.resolveDocument();
 		}