瀏覽代碼

do not add unused import declarations to execution flow (#2134)

* do not add unused import declarations to execution flow

improves code generation performance / simulation performance for models
that import a lot of external declarations with only a few used.

* removed tests that are not required
Andreas Mülder 7 年之前
父節點
當前提交
f5e9865485

+ 21 - 24
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/transformation/StructureMapping.xtend

@@ -12,12 +12,13 @@ package org.yakindu.sct.model.sexec.transformation
 
 import com.google.inject.Inject
 import java.util.ArrayList
-import org.eclipse.emf.ecore.resource.URIConverter
+import java.util.Set
+import org.eclipse.emf.ecore.EObject
 import org.eclipse.xtext.EcoreUtil2
 import org.eclipse.xtext.naming.IQualifiedNameProvider
+import org.yakindu.base.expressions.expressions.ElementReferenceExpression
 import org.yakindu.base.types.Declaration
 import org.yakindu.base.types.Operation
-import org.yakindu.base.types.Package
 import org.yakindu.base.types.Property
 import org.yakindu.sct.model.sexec.ExecutionFlow
 import org.yakindu.sct.model.sexec.ExecutionRegion
@@ -32,20 +33,16 @@ import org.yakindu.sct.model.sgraph.Scope
 import org.yakindu.sct.model.sgraph.State
 import org.yakindu.sct.model.sgraph.Statechart
 import org.yakindu.sct.model.sgraph.Vertex
-import org.yakindu.sct.model.stext.scoping.IPackageImport2URIMapper
 import org.yakindu.sct.model.stext.stext.EventDefinition
 import org.yakindu.sct.model.stext.stext.ImportScope
 import org.yakindu.sct.model.stext.stext.OperationDefinition
 import org.yakindu.sct.model.stext.stext.VariableDefinition
-import org.eclipse.emf.ecore.EObject
 
 class StructureMapping {
 	 
 	@Inject extension SexecElementMapping mapping
 	@Inject extension StatechartExtensions sct
 	@Inject extension IQualifiedNameProvider
-	@Inject
-	private IPackageImport2URIMapper mapper;
 	
 	
 	//==========================================================================
@@ -57,15 +54,26 @@ class StructureMapping {
 	 * This includes creating the scopes and adding all relevant declarations. Empty scopes wont be mapped.
 	 */
 	def ExecutionFlow mapScopes(Statechart sc, ExecutionFlow flow) {
-		flow.scopes.addAll(sc.scopes.map(scope | scope.mapScope))
+		val usedDeclarations = sc.importedDeclarations
+		flow.scopes.addAll(sc.scopes.map(scope | scope.mapScope(usedDeclarations)))
 		flow
 	}
 	
+	/**
+	 * @return A set of used declaration that are imported from an external resource
+	 */
+	def protected importedDeclarations(Statechart it) {
+		val allDeclarations = it.eAllContents.filter(ElementReferenceExpression).map[reference].filter(Declaration).toSet
+		return if(it.eResource !== null)
+			allDeclarations.filter[decl|!decl.eResource.URI.equals(it.eResource.URI)].toSet
+		else allDeclarations
+	}
+	
 	
 	/**
 	 *  Interface and internal scopes have declarations
 	 */
-	def dispatch Scope mapScope(Scope scope) {
+	def dispatch Scope mapScope(Scope scope, Set<Declaration> usedDeclarationss) {
 		val _scope = scope.createScope
 		_scope.declarations.addAll(scope.declarations.map(decl | decl.map).filterNull)
 		return _scope
@@ -74,17 +82,9 @@ class StructureMapping {
 	/**
 	 * Import scope has imports which needs to be resolved to get all imported variable and operation definitions
 	 */
-	def dispatch Scope mapScope(ImportScope scope) {
+	def dispatch Scope mapScope(ImportScope scope, Set<Declaration> usedDeclarations) {
 		val _scope = scope.createScope
-		for (String importString : scope.imports){
-			val pkgImport = mapper.findPackageImport(scope.eResource,importString)
-			
-			if (pkgImport.isPresent && URIConverter.INSTANCE.exists(pkgImport.get.getUri(), null)) {
-				val packageForNamespace = scope.eResource.resourceSet.getResource(pkgImport.get.uri, true).contents.
-					head as Package
-				packageForNamespace.member.filter(Declaration).toList.forEach[createImportDeclaration(_scope)]
-			}
-		}
+		usedDeclarations.forEach[createImportDeclaration(_scope)]
 		return _scope
 	}
 	
@@ -111,17 +111,14 @@ class StructureMapping {
 	}
 	
 	def dispatch Declaration map(EventDefinition e) {
-		val _e = e.create
-		return _e
+		e.create
 	}
 	
 	def dispatch Declaration map(VariableDefinition v) {
-		val _v = v.create
-		return _v
+		v.create
 	}
 	def dispatch Declaration map(OperationDefinition v) {
-		val _v = v.create
-		return _v
+		v.create
 	}
 	 
 	

+ 23 - 58
plugins/org.yakindu.sct.simulation.core.sexec/src/org/yakindu/sct/simulation/core/sexec/container/DefaultExecutionContextInitializer.xtend

@@ -11,13 +11,9 @@
 package org.yakindu.sct.simulation.core.sexec.container
 
 import com.google.inject.Inject
-import java.util.HashSet
 import java.util.List
-import java.util.Set
-import org.eclipse.emf.ecore.util.EcoreUtil
 import org.eclipse.xtext.EcoreUtil2
 import org.eclipse.xtext.naming.IQualifiedNameProvider
-import org.yakindu.base.expressions.expressions.ElementReferenceExpression
 import org.yakindu.base.types.Declaration
 import org.yakindu.base.types.Direction
 import org.yakindu.base.types.Package
@@ -44,7 +40,6 @@ import org.yakindu.sct.model.stext.stext.VariableDefinition
 /**
  * 
  * @author andreas muelder - Initial contribution and API
- * @author axel terfloth - added functionality to filter unused declaration roots
  * 
  */
 class DefaultExecutionContextInitializer implements IExecutionContextInitializer {
@@ -55,41 +50,24 @@ class DefaultExecutionContextInitializer implements IExecutionContextInitializer
 	@Inject protected extension ITypeValueProvider
 	@Inject protected extension SExecExtensions
 
-	protected boolean mapUnusedDaclarationRoots = false
-	
+	extension SRuntimeFactory = SRuntimeFactory.eINSTANCE
+
 	override initialize(ExecutionContext context, ExecutionFlow flow) {
 		flow.scopes.forEach[context.slots += transform]
 	}
 
-	/**
-	 * Hook that decides if unused declarations in import scopes should be transformed to execution slots.
-	 * Subclasses may override this hook.
-	 * 
-	 * @return - false by default
-	 */	
-	def isMapUnusedDeclarationRootsInImportScope() { mapUnusedDaclarationRoots }
-
-	def setMapUnusedDeclarationRootsInImportScope(boolean b) { mapUnusedDaclarationRoots = b }
-	
-	
-	def create it : SRuntimeFactory.eINSTANCE.createCompositeSlot importSlot(ExecutionFlow flow) {
+	def create it : createCompositeSlot importSlot(ExecutionFlow flow) {
 		it => [
 			name = "imports"
 		]
 	}
 
 	def dispatch ExecutionSlot transform(ImportScope scope) {
-		
+
 		val composite = importSlot(scope.flow)
-		
-		val usedDeclarations = scope.flow.usedDeclarationRoots
-		
+
 		// retrieve namespaces from variable names and create corresponding composite slots
-		for (Declaration decl : scope.declarations
-										.filter(ImportDeclaration)
-										.map[declaration]
-										.filter(decl | mapUnusedDeclarationRootsInImportScope || usedDeclarations.exists[used | EcoreUtil.equals(decl,used)])) 
-		{
+		for (Declaration decl : scope.declarations.filter(ImportDeclaration).map[declaration]) {
 			val pkg = EcoreUtil2.getContainerOfType(decl, Package)
 			if (pkg !== null) {
 				val namespace = pkg.name
@@ -97,8 +75,8 @@ class DefaultExecutionContextInitializer implements IExecutionContextInitializer
 				val declName = decl.name
 				val slot = composite.slots.getSlotFor(pkgHeader)
 				val declarationSlot = decl.transform
-				declarationSlot.setFqName(namespace + "." + declName)
-				declarationSlot.setName(declName)
+				declarationSlot.fqName = namespace + "." + declName
+				declarationSlot.name = declName
 				// only add imported variables/events when they have not yet been imported
 				if (!slot.slots.exists[fqName == declarationSlot.fqName]) {
 					slot.slots += declarationSlot
@@ -110,27 +88,26 @@ class DefaultExecutionContextInitializer implements IExecutionContextInitializer
 		composite
 	}
 
-	def getSlotFor(List<ExecutionSlot> slots, String name) {
+	def protected getSlotFor(List<ExecutionSlot> slots, String name) {
 		val existingSlot = slots.findFirst[it.name == name]
-		if (existingSlot !== null && existingSlot instanceof CompositeSlot) {
-			existingSlot as CompositeSlot
-		} else {
-			val newSlot = SRuntimeFactory.eINSTANCE.createCompositeSlot
-			newSlot.name = name
-			slots += newSlot
-			newSlot
-		}
+		if (existingSlot instanceof CompositeSlot) {
+			existingSlot
+		} else
+			createCompositeSlot => [ newSlot |
+				newSlot.name = name
+				slots += newSlot
+			]
 	}
 
 	def dispatch ExecutionSlot transform(InternalScope scope) {
-		SRuntimeFactory.eINSTANCE.createCompositeSlot => [
+		createCompositeSlot => [
 			name = "internal"
 			scope.declarations.forEach[decl|it.slots += decl.transform]
 		]
 	}
 
 	def dispatch ExecutionSlot transform(Scope scope) {
-		SRuntimeFactory.eINSTANCE.createCompositeSlot => [
+		createCompositeSlot => [
 			name = "time events"
 			scope.declarations.forEach[decl|slots += decl.transform]
 		]
@@ -139,7 +116,7 @@ class DefaultExecutionContextInitializer implements IExecutionContextInitializer
 	def dispatch ExecutionSlot transform(InterfaceScope scope) {
 		val flow = EcoreUtil2.getContainerOfType(scope, ExecutionFlow)
 		val namespace = (flow.sourceElement as Statechart).namespace
-		SRuntimeFactory.eINSTANCE.createCompositeSlot => [
+		createCompositeSlot => [
 			if (scope.name !== null) {
 				name = scope.name
 				val scopeFqn = scope.fullyQualifiedName.toString
@@ -152,7 +129,7 @@ class DefaultExecutionContextInitializer implements IExecutionContextInitializer
 	}
 
 	def dispatch ExecutionSlot transform(VariableDefinition variable) {
-		SRuntimeFactory.eINSTANCE.createExecutionVariable => [
+		createExecutionVariable => [
 			name = variable.fullyQualifiedName.lastSegment
 			fqName = variable.fullyQualifiedName.toString
 			type = variable.infer.type
@@ -162,7 +139,7 @@ class DefaultExecutionContextInitializer implements IExecutionContextInitializer
 	}
 
 	def dispatch ExecutionSlot transform(EventDefinition event) {
-		SRuntimeFactory.eINSTANCE.createExecutionEvent => [
+		createExecutionEvent => [
 			name = event.fullyQualifiedName.lastSegment
 			fqName = event.fullyQualifiedName.toString
 			type = event.type
@@ -172,7 +149,7 @@ class DefaultExecutionContextInitializer implements IExecutionContextInitializer
 	}
 
 	def dispatch ExecutionSlot transform(OperationDefinition op) {
-		SRuntimeFactory.eINSTANCE.createExecutionOperation => [
+		createExecutionOperation => [
 			name = op.fullyQualifiedName.lastSegment
 			fqName = op.fullyQualifiedName.toString
 			type = if(op.type !== null) op.type else getType(ITypeSystem.VOID)
@@ -181,23 +158,11 @@ class DefaultExecutionContextInitializer implements IExecutionContextInitializer
 	}
 
 	def dispatch ExecutionSlot transform(TimeEvent event) {
-		SRuntimeFactory.eINSTANCE.createExecutionEvent => [
+		createExecutionEvent => [
 			name = event.fullyQualifiedName.lastSegment
 			fqName = event.fullyQualifiedName.toString
 			type = getType(ITypeSystem.INTEGER)
 			value = type.defaultValue
 		]
 	}
-
-	
-	/**
-	 * @return A set of used declaration roots.
-	 */
-	def protected usedDeclarationRoots(ExecutionFlow flow) {
-		val Set<Declaration> usedDecls = new HashSet<Declaration>()
-		
-		if (flow !== null) flow.eAllContents.filter(typeof(ElementReferenceExpression)).map( ere | ere.reference ).filter(typeof(Declaration)).forEach[ decl | usedDecls += decl]
-		
-		return usedDecls
-	}
 }

+ 1 - 1
test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/ModelSequencerTest.java

@@ -37,7 +37,7 @@ import com.google.inject.name.Names;
  * @author axel terfloth
  *
  */
-public class ModelSequencerTest extends Assert {
+public abstract class ModelSequencerTest extends Assert {
 
 	@Inject
 	protected IModelSequencer sequencer;

+ 5 - 3
test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/ModelSequencertDeclarationsTest.java

@@ -52,6 +52,8 @@ import org.yakindu.sct.model.stext.stext.OperationDefinition;
 import org.yakindu.sct.model.stext.stext.ReactionEffect;
 import org.yakindu.sct.model.stext.stext.ReactionTrigger;
 import org.yakindu.sct.model.stext.stext.VariableDefinition;
+
+import com.google.common.collect.Sets;
 public class ModelSequencertDeclarationsTest extends ModelSequencerTest {
 
 	/**
@@ -60,7 +62,7 @@ public class ModelSequencertDeclarationsTest extends ModelSequencerTest {
 	@Test
 	public void testScopeName() {
 		InterfaceScope scope = _createInterfaceScope("abc", null);
-		assertEquals(scope.getName(), ((InterfaceScope) structureMapping.mapScope(scope)).getName());
+		assertEquals(scope.getName(), ((InterfaceScope) structureMapping.mapScope(scope, Sets.newHashSet())).getName());
 	}
 
 	/**
@@ -69,7 +71,7 @@ public class ModelSequencertDeclarationsTest extends ModelSequencerTest {
 	@Test
 	public void testMapEmptyInternalScope() {
 		InternalScope scope = _createInternalScope(null);
-		Scope _scope = structureMapping.mapScope(scope);
+		Scope _scope = structureMapping.mapScope(scope, Sets.newHashSet());
 
 		assertTrue(_scope instanceof InternalScope);
 	}
@@ -83,7 +85,7 @@ public class ModelSequencertDeclarationsTest extends ModelSequencerTest {
 		EventDefinition e2 = _createEventDefinition("e2", scope);
 		VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER, scope);
 
-		Scope _scope = structureMapping.mapScope(scope);
+		Scope _scope = structureMapping.mapScope(scope, Sets.newHashSet());
 
 		assertTrue(_scope instanceof InterfaceScope);
 		assertEquals(3, _scope.getDeclarations().size());