Commit 4a3fbc68 authored by Daniel Honsel's avatar Daniel Honsel
Browse files

improved performance

- added own reference finder
- search only in modules for possible references, that import the defining module
parent 5a1abe36
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
package de.ugoe.cs.swe.common;

import java.util.Queue;
import java.util.Set;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.util.InternalEList;

import com.google.common.collect.Lists;

public class TTCN3ReferenceHelper {

	/**
	 * Own implementation of org.eclipse.xtext.EcoreUtil2::findCrossReferences
	 * that returns true after the first reference occurred, otherwise false.
	 */
	public static boolean isReferenced(EObject rootElement, Set<? extends EObject> targets) {
		Queue<EObject> elements = Lists.newLinkedList();
		elements.add(rootElement);

		while (!elements.isEmpty()) {
			if (findChildElements(targets, elements))
				return true;
		}

		return false;
	}

	@SuppressWarnings("unchecked")
	private static boolean findChildElements(final Set<? extends EObject> targets, Queue<EObject> elements) {
		EObject rootElement = elements.poll();

		for (EReference ref : rootElement.eClass().getEAllReferences()) {
			if (rootElement.eIsSet(ref)) {
				if (ref.isContainment()) {
					Object content = rootElement.eGet(ref, false);
					if (ref.isMany()) {
						InternalEList<EObject> contentList = (InternalEList<EObject>) content;
						for (int i = 0; i < contentList.size(); ++i) {
							EObject childElement = contentList.basicGet(i);
							if (!childElement.eIsProxy())
								elements.add(childElement);
						}
					} else {
						EObject childElement = (EObject) content;
						if (!childElement.eIsProxy())
							elements.add(childElement);
					}
				} else if (!ref.isContainer()) {
					if (checkNoContainerElements(rootElement, targets, ref))
						return true;
				}
			}
		}
		return false;
	}

	@SuppressWarnings({ "unchecked" })
	private static boolean checkNoContainerElements(EObject rootElement, final Set<? extends EObject> targets, EReference ref) {
		Object value = rootElement.eGet(ref, false);
		if (ref.isMany()) {
			InternalEList<EObject> values = (InternalEList<EObject>) value;
			for (int i = 0; i < values.size(); ++i) {
				EObject refElement = values.get(i);
				if (targets.contains(refElement)) {
					return true;
				}
			}
		} else {
			EObject refElement = (EObject) value;
			if (targets.contains(refElement)) {
				return true;
			}
		}
		return false;
	}

}
+14 −28
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ import com.google.common.base.Strings
import de.ugoe.cs.swe.TTCN3Configuration.QualityCheckProfile
import de.ugoe.cs.swe.common.ConfigTools
import de.ugoe.cs.swe.common.MiscTools
import de.ugoe.cs.swe.common.TTCN3ElementReferenceAcceptor
import de.ugoe.cs.swe.common.logging.LoggingInterface.LogLevel
import de.ugoe.cs.swe.common.logging.LoggingInterface.MessageClass
import de.ugoe.cs.swe.tTCN3.AltConstruct
@@ -71,6 +70,7 @@ import org.eclipse.xtext.validation.AbstractDeclarativeValidator
import org.eclipse.xtext.validation.Check
import org.eclipse.xtext.validation.EValidatorRegistrar

import static extension de.ugoe.cs.swe.common.TTCN3ReferenceHelper.*
import static extension de.ugoe.cs.swe.common.TTCN3ScopeHelper.*
import static extension org.eclipse.xtext.EcoreUtil2.*

@@ -84,6 +84,7 @@ class CodeStyleValidator extends AbstractDeclarativeValidator {
	val ConfigTools configTools = ConfigTools.getInstance;
	var QualityCheckProfile activeProfile = configTools.selectedProfile as QualityCheckProfile
	final Stopwatch stopwatch = Stopwatch.createUnstarted();
	final TTCN3StatisticsProvider statistics = TTCN3StatisticsProvider.getInstance

	@Check
	def checkNoGotoStatements(GotoStatement goto) {
@@ -605,45 +606,30 @@ class CodeStyleValidator extends AbstractDeclarativeValidator {
	}

	// TODO: figure out another way to find referenced objects
	private def boolean isUnreferenced(EObject type, EObject parent) {
	private def boolean isUnreferenced(EObject type, TTCN3Module parent) {
		stopwatch.start

		val target = newHashSet(type);
		val TTCN3ElementReferenceAcceptor acceptor = new TTCN3ElementReferenceAcceptor()

		parent.findCrossReferences(target, acceptor)
		var boolean found = parent.isReferenced(target)

		stopwatch.stop

		System.err.println("Finding cross references 1 took: " + stopwatch.toString)
		
		stopwatch.reset
		stopwatch.start
		
		// TODO: do not call this for all objects
		// TODO: improve performance (hit list for resources which are often called successfully?)
		// TODO: write own findCrossReferences?
		// TODO: cache found referenced objects?
		// TODO: consider only resources that are importing the current one!
		
		if (!acceptor.foundReference) {
		if (!found) {
			for (r : parent.resourceSet.resources) {
				r.allContents.next.findCrossReferences(target, acceptor)
				if (acceptor.foundReference) {
					stopwatch.stop
					System.err.println("Finding cross references 2 took: " + stopwatch.toString)
					return false;
				val TTCN3Module currentBase = statistics.getModule(r)

				// only consider modules that are importing the current module
				if (statistics.isBaseModuleImported(parent, currentBase.name)) {
					if (currentBase.isReferenced(target)) {
						return false
					}
				}
			}
		}

		stopwatch.stop
		
		System.err.println("Finding cross references 2 took: " + stopwatch.toString)
		
		stopwatch.reset

		return !acceptor.foundReference
		return !found
	}

	@Check
+3 −18
Original line number Diff line number Diff line
package de.ugoe.cs.swe.validation

import de.ugoe.cs.swe.TTCN3Configuration.QualityCheckProfile
import de.ugoe.cs.swe.common.ConfigTools
import de.ugoe.cs.swe.tTCN3.ImportDef
import de.ugoe.cs.swe.tTCN3.TTCN3Module

import org.eclipse.xtext.validation.AbstractDeclarativeValidator
import org.eclipse.xtext.validation.Check
import org.eclipse.xtext.validation.EValidatorRegistrar

import static extension org.eclipse.xtext.EcoreUtil2.*

class MiscFeatureValidator extends AbstractDeclarativeValidator {
	val ConfigTools configTools = ConfigTools.getInstance;
	var QualityCheckProfile activeProfile = configTools.selectedProfile as QualityCheckProfile

	@Check
	def addModuleToStatisticProvider(TTCN3Module module) {
@@ -22,16 +14,9 @@ class MiscFeatureValidator extends AbstractDeclarativeValidator {
		TTCN3StatisticsProvider.getInstance().addModule(module);
	}

	@Check
	def listImports(TTCN3Module module) {
		if (activeProfile.featureListImportedModuleNames || activeProfile.featureListImportedModuleFileNames ||
			activeProfile.featureListImportingModuleNames || activeProfile.featureListImportingModuleFileNames) {

			for (i : module.getAllContentsOfType(ImportDef)) {
				TTCN3StatisticsProvider.getInstance().addImport(module.name, i.name)
			}
		}
	}
	// initialization moved to CodeStyleValidator::isUnreferenced
	//	@Check
	//	def listImports(TTCN3Module module)

	override register(EValidatorRegistrar registrar) {
		//not needed for classes used as ComposedCheck
+59 −17
Original line number Diff line number Diff line
package de.ugoe.cs.swe.validation;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import de.ugoe.cs.swe.common.MiscTools;
import de.ugoe.cs.swe.common.logging.LoggingInterface;
import de.ugoe.cs.swe.common.logging.LoggingInterface.MessageClass;
import de.ugoe.cs.swe.tTCN3.ImportDef;
import de.ugoe.cs.swe.tTCN3.TTCN3Module;

public class TTCN3StatisticsProvider {
	private Map<String, TTCN3Module> modules = Maps.newHashMap();
	private Map<String, List<String>> imports = Maps.newHashMap();
	private Map<String, List<String>> importedModules = Maps.newHashMap();
	private final Map<String, TTCN3Module> modules = Maps.newHashMap();
	private final Map<String, Set<String>> imports = Maps.newHashMap();
	private final Map<String, Set<String>> importedModules = Maps.newHashMap();

	private int parsedLines;
	private long parseTime;
@@ -31,6 +36,7 @@ public class TTCN3StatisticsProvider {
	private int countStructure;
	private int countStyle;
	private int countModularization;
	private boolean importsInitialized;

	public int getCountNaming() {
		return countNaming;
@@ -113,18 +119,18 @@ public class TTCN3StatisticsProvider {
		modules.put(module.getName(), module);
	}

	public void addImport(String module, String importedModule) {
	private void addImport(String module, String importedModule) {
		if (imports.containsKey(module)) {
			imports.get(module).add(importedModule);
		} else {
			List<String> importedModules = Lists.newArrayList();
			Set<String> importedModules = Sets.newHashSet();
			importedModules.add(importedModule);
			imports.put(module, importedModules);
		}
		if (importedModules.containsKey(importedModule)) {
			importedModules.get(importedModule).add(module);
		} else {
			List<String> modules = Lists.newArrayList();
			Set<String> modules = Sets.newHashSet();
			modules.add(module);
			importedModules.put(importedModule, modules);
		}
@@ -138,7 +144,7 @@ public class TTCN3StatisticsProvider {
		printImportModuleNames(fileNames, logger, importedModules, false);
	}

	private void printImportModuleNames(boolean fileNames, LoggingInterface logger, Map<String, List<String>> map, boolean importing) {
	private void printImportModuleNames(boolean fileNames, LoggingInterface logger, Map<String, Set<String>> map, boolean importing) {
		for (String moduleName : map.keySet()) {
			TTCN3Module module = modules.get(moduleName);
			if (module != null) {
@@ -169,8 +175,8 @@ public class TTCN3StatisticsProvider {
				} else {
					message = "Module \"" + module.getName() + "\" is imported in module(s) \"" + importList + "\"";
				}
				logger.logInformation(module.eResource().getURI(), node.getStartLine(), node.getEndLine(), MessageClass.GENERAL,
						message, "1.18, " + MiscTools.getMethodName());
				logger.logInformation(module.eResource().getURI(), node.getStartLine(), node.getEndLine(), MessageClass.GENERAL, message,
						"1.18, " + MiscTools.getMethodName());
			}
		}
	}
@@ -200,4 +206,40 @@ public class TTCN3StatisticsProvider {
		this.analyzeTime += analyzeTime;
	}

	public boolean isBaseModuleImported(TTCN3Module base, String other) {
		if (!importsInitialized)
			initializeImports(base);

		if (importedModules.containsKey(base.getName()) && importedModules.get(base.getName()).contains(other)) {
			return true;
		} else {
			return false;
		}
	}

	private void initializeImports(TTCN3Module module) {
		for (Resource r : module.eResource().getResourceSet().getResources()) {
			TTCN3Module currentModule = getModule(r);
			for (ImportDef i : EcoreUtil2.getAllContentsOfType(currentModule, ImportDef.class)) {
				addImport(currentModule.getName(), i.getName());
			}
		}
		importsInitialized = true;
	}

	public TTCN3Module getModule(Resource resource) {
		final TreeIterator<EObject> contentIterator = resource.getAllContents();
		while (contentIterator.hasNext()) {
			final EObject next = contentIterator.next();
			if (next instanceof TTCN3Module) {
				return (TTCN3Module) next;
			}
		}
		return null;
	}

	public boolean isImportsInitialized() {
		return importsInitialized;
	}

}
+5 −5

File changed.

Contains only whitespace changes.