<commit_before>package org.strategoxt.imp.runtime.services;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.imp.language.Language;
import org.eclipse.imp.language.LanguageRegistry;
import org.eclipse.imp.model.ISourceProject;
import org.eclipse.imp.model.ModelFactory;
import org.eclipse.imp.model.ModelFactory.ModelException;
import org.eclipse.imp.parser.IParseController;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.strategoxt.imp.runtime.Environment;
import org.strategoxt.imp.runtime.dynamicloading.BadDescriptorException;
import org.strategoxt.imp.runtime.dynamicloading.Descriptor;
import org.strategoxt.imp.runtime.parser.SGLRParseController;
import org.strategoxt.imp.runtime.stratego.EditorIOAgent;
import org.strategoxt.imp.runtime.stratego.SourceAttachment;

public class StrategoObserverBackgroundUpdateJob implements StrategoAnalysisJob {

	private final IPath path;
	private final IProject project;
	private StrategoProgressMonitor progress;
	private StrategoObserver observer;
	private SGLRParseController parseController;
	
	public StrategoObserverBackgroundUpdateJob(IPath path, IProject project) {
		this.path = path;
		this.project = project;
	}
	
	public IStatus analyze(IProgressMonitor monitor) {
		
		this.progress = new StrategoProgressMonitor(monitor);
		
		try {
			
			IPath absolutePath = project == null ? path : project.getLocation().append(path);
			
			// Get descriptor
			Language lang = LanguageRegistry.findLanguage(absolutePath, null);
			if (lang == null) {
				Environment.logException("Could not determine language for queued analysis of " + absolutePath);
				return Status.OK_STATUS;
			}
			Descriptor descriptor = Environment.getDescriptor(lang); 
			
			// Get parse controller
			parseController = descriptor.createService(SGLRParseController.class, null);
			observer = descriptor.createService(StrategoObserver.class, parseController);
			
			observer.getLock().lock();
			try {
				((EditorIOAgent)observer.getRuntime().getIOAgent()).setJob(this);
				// Don't perform initial (foreground) update
				parseController.setPerformInitialUpdate(false);
				
				// Read file
				File file = absolutePath.toFile();
				String input = readFile(file);
			
			    // Parse file
			    ISourceProject sproject = ModelFactory.open(project);
			    
			    parseController.initialize(path, sproject, null);
			    IStrategoTerm ast = parseController.parse(input, new NullProgressMonitor());
			    if (ast == null) {
			    	// HACK: default to () as the AST
			    	parseController.internalSetAst(makeFakeAST(parseController, file));
			    }
				
			    observer.update(parseController, monitor);
			} finally {
				observer.getLock().unlock();
			}
		    <commit_msg>Possible fix for memory leak of Spoofax/494 for observers loaded by editors and background jobs<commit_after>package org.strategoxt.imp.runtime.services;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.imp.language.Language;
import org.eclipse.imp.language.LanguageRegistry;
import org.eclipse.imp.model.ISourceProject;
import org.eclipse.imp.model.ModelFactory;
import org.eclipse.imp.model.ModelFactory.ModelException;
import org.eclipse.imp.parser.IParseController;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.strategoxt.imp.runtime.Environment;
import org.strategoxt.imp.runtime.dynamicloading.BadDescriptorException;
import org.strategoxt.imp.runtime.dynamicloading.Descriptor;
import org.strategoxt.imp.runtime.parser.SGLRParseController;
import org.strategoxt.imp.runtime.stratego.EditorIOAgent;
import org.strategoxt.imp.runtime.stratego.SourceAttachment;

public class StrategoObserverBackgroundUpdateJob implements StrategoAnalysisJob {

	private final IPath path;
	private final IProject project;
	private StrategoProgressMonitor progress;
	private StrategoObserver observer;
	private SGLRParseController parseController;
	
	public StrategoObserverBackgroundUpdateJob(IPath path, IProject project) {
		this.path = path;
		this.project = project;
	}
	
	public IStatus analyze(IProgressMonitor monitor) {
		
		this.progress = new StrategoProgressMonitor(monitor);
		
		try {
			
			IPath absolutePath = project == null ? path : project.getLocation().append(path);
			
			// Get descriptor
			Language lang = LanguageRegistry.findLanguage(absolutePath, null);
			if (lang == null) {
				Environment.logException("Could not determine language for queued analysis of " + absolutePath);
				return Status.OK_STATUS;
			}
			Descriptor descriptor = Environment.getDescriptor(lang); 
			
			// Get parse controller
			parseController = descriptor.createService(SGLRParseController.class, null);
			observer = descriptor.createService(StrategoObserver.class, parseController);
			
			observer.getLock().lock();
			try {
				((EditorIOAgent)observer.getRuntime().getIOAgent()).setJob(this);
				// Don't perform initial (foreground) update
				parseController.setPerformInitialUpdate(false);
				
				// Read file
				File file = absolutePath.toFile();
				String input = readFile(file);
			
			    // Parse file
			    ISourceProject sproject = ModelFactory.open(project);
			    
			    parseController.initialize(path, sproject, null);
			    IStrategoTerm ast = parseController.parse(input, new NullProgressMonitor());
			    if (ast == null) {
			    	// HACK: default to () as the AST
			    	parseController.internalSetAst(makeFakeAST(parseController, file));
			    }
				
			    observer.update(parseController, monitor);
			} finally {
				observer.getLock().unlock();
				observer.uninitialize();
			}
		    
{'fraction_non_alphanumeric': 0.09689049121225778, 'fraction_numerical': 0.0004506534474988734, 'mean_word_length': 4.613827993254637, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5112662', 'n_tokens_mistral': 2119, 'n_tokens_neox': 1838, 'n_words': 371}