Bug 516271: [codegen][cdt] CDT integration throws exception when a
capsule has no behaviour

- Added utilities to pre-compute the containment chains of elements
before flattening state machines.

Change-Id: I64d788ab397018ac9896da9ae8f310a724a19d37
Signed-off-by: Ernesto Posse <eposse@gmail.com>
diff --git a/plugins/umlrt/codegen/org.eclipse.papyrusrt.codegen.statemachines.flat/src/org/eclipse/papyrusrt/codegen/statemachines/transformations/ContainmentChainsPreprocessor.xtend b/plugins/umlrt/codegen/org.eclipse.papyrusrt.codegen.statemachines.flat/src/org/eclipse/papyrusrt/codegen/statemachines/transformations/ContainmentChainsPreprocessor.xtend
new file mode 100644
index 0000000..ace74fe
--- /dev/null
+++ b/plugins/umlrt/codegen/org.eclipse.papyrusrt.codegen.statemachines.flat/src/org/eclipse/papyrusrt/codegen/statemachines/transformations/ContainmentChainsPreprocessor.xtend
@@ -0,0 +1,87 @@
+/*****************************************************************************
+ * Copyright (c) 2017 Zeligsoft (2009) Ltd. and others.
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *   Ernesto Posse - Initial API and implementation
+ *****************************************************************************/
+
+package org.eclipse.papyrusrt.codegen.statemachines.transformations
+
+import org.eclipse.papyrusrt.codegen.CodeGenPlugin
+import org.eclipse.papyrusrt.xtumlrt.common.NamedElement
+import org.eclipse.papyrusrt.xtumlrt.statemach.CompositeState
+import org.eclipse.papyrusrt.xtumlrt.statemach.SimpleState
+import org.eclipse.papyrusrt.xtumlrt.statemach.State
+import org.eclipse.papyrusrt.xtumlrt.statemach.StateMachine
+import org.eclipse.papyrusrt.xtumlrt.statemach.Transition
+import static extension org.eclipse.papyrusrt.xtumlrt.util.ContainmentUtils.*
+
+/**
+ * This visitor goes through the state machine before flattening to pre-compute the full
+ * containment chain of all elements. This is needed because the flattening process changes, by
+ * definition the containment relationships and therefore the qualified names of elements, but
+ * the original qualified names are needed to disambiguate element in the generated code.
+ * 
+ * <p> This is implemented as a simple visitor on state machine elements which invokes the
+ * {@link org.eclipse.papyrusrt.xtumlrt.util.ContainmentUtils.cachedContainmentChain} method on 
+ * each element. Since that method caches the list, subsequent invocations of that method in the 
+ * generator, will return the original qualified name.
+ * 
+ * @author epp
+ */
+class ContainmentChainsPreprocessor {
+
+	public static val INSTANCE = new ContainmentChainsPreprocessor
+
+	def boolean cacheAllChains(StateMachine stateMachine) {
+		try {
+			visit(stateMachine)
+			return true
+		} catch (Exception e) {
+			CodeGenPlugin.error("[QualifiedNamePreprocessor] error preprocessing state machine", e)
+			return false
+		}
+	}
+
+	dispatch def void visit(StateMachine stateMachine) {
+		stateMachine.cachedFullContainmentChain
+		if (stateMachine.top !== null)
+			visit(stateMachine.top)
+	}
+
+	dispatch def void visit(CompositeState state) {
+		visitState(state)
+		state.initial?.cachedFullContainmentChain
+		state.deepHistory?.cachedFullContainmentChain
+		state.choicePoints.forEach[cachedFullContainmentChain]
+		state.junctionPoints.forEach[cachedFullContainmentChain]
+		state.substates.forEach[visit]
+		state.transitions.forEach[visit]
+	}
+
+	dispatch def void visit(SimpleState state) {
+		visitState(state)
+	}
+
+	private def void visitState(State state) {
+		state.cachedFullContainmentChain
+		state.entryPoints.forEach[cachedFullContainmentChain]
+		state.exitPoints.forEach[cachedFullContainmentChain]
+	}
+
+	dispatch def void visit(Transition transition) {
+		transition.cachedFullContainmentChain
+		transition.triggers.forEach[cachedFullContainmentChain]
+		transition.guard?.cachedFullContainmentChain
+		transition.actionChain?.cachedFullContainmentChain
+	}
+
+	dispatch def void visit(NamedElement element) {
+		element?.cachedFullContainmentChain
+	}
+}
diff --git a/plugins/umlrt/codegen/org.eclipse.papyrusrt.codegen.statemachines.flat/src/org/eclipse/papyrusrt/codegen/statemachines/transformations/FlatteningTransformer.xtend b/plugins/umlrt/codegen/org.eclipse.papyrusrt.codegen.statemachines.flat/src/org/eclipse/papyrusrt/codegen/statemachines/transformations/FlatteningTransformer.xtend
index e55becb..1da360b 100644
--- a/plugins/umlrt/codegen/org.eclipse.papyrusrt.codegen.statemachines.flat/src/org/eclipse/papyrusrt/codegen/statemachines/transformations/FlatteningTransformer.xtend
+++ b/plugins/umlrt/codegen/org.eclipse.papyrusrt.codegen.statemachines.flat/src/org/eclipse/papyrusrt/codegen/statemachines/transformations/FlatteningTransformer.xtend
@@ -46,10 +46,10 @@
      */
     val Set<CommonElement> newElementsSet = newHashSet
 
+    val containmentPreProcessor = new ContainmentChainsPreprocessor
     val qualNamesPreProcessor   = new QualifiedNamePreprocessor
     val depthPreProcessor       = new DepthPreprocessor
     val deepHistoryAdder        = new DeepHistoryAdder
-    val inheritanceFlattener    = new StateMachineInheritanceFlattener
     val nestingFlattener        = new StateNestingFlattener
 
     @Data static class FlatteningTransformationContext implements TransformationContext
@@ -94,6 +94,11 @@
         result = depthPreProcessor.cacheAllDepths( stateMachine )
         if (!result) return new TransformationResult( result, stateMachine, null )
 
+        // We precompute the full containment chains for all elements of the
+        // state machine.
+        result = containmentPreProcessor.cacheAllChains( stateMachine )
+        if (!result) return new TransformationResult( result, stateMachine, null )
+
         // We precompute the fully qualified names for all elements of the
         // state machine so that they can be used by the C++ generator for the
         // corresponding C++ methods.
diff --git a/plugins/xtumlrt/common/org.eclipse.papyrusrt.xtumlrt.util/src/org/eclipse/papyrusrt/xtumlrt/util/ContainmentUtils.xtend b/plugins/xtumlrt/common/org.eclipse.papyrusrt.xtumlrt.util/src/org/eclipse/papyrusrt/xtumlrt/util/ContainmentUtils.xtend
new file mode 100644
index 0000000..138ab74
--- /dev/null
+++ b/plugins/xtumlrt/common/org.eclipse.papyrusrt.xtumlrt.util/src/org/eclipse/papyrusrt/xtumlrt/util/ContainmentUtils.xtend
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * Copyright (c) 2017 Zeligsoft (2009) Ltd. and others.
+ * 
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *   Ernesto Posse - Initial API and implementation
+ *****************************************************************************/
+
+package org.eclipse.papyrusrt.xtumlrt.util
+
+import java.util.List
+import org.eclipse.papyrusrt.xtumlrt.common.NamedElement
+import static extension org.eclipse.papyrusrt.xtumlrt.util.XTUMLRTUtil.*
+
+/**
+ * Utilities related to containment relationships.
+ * 
+ * <p>Utilities here are useful to record containment chains, since containment structure may be changed by flattening.
+ * 
+ * @author epp
+ */
+class ContainmentUtils {
+
+	static val INSTANCE = new ContainmentUtils
+
+	def List<NamedElement> create {
+		val owner = element.owner
+		var List<NamedElement> chain
+		if (owner === null) {
+			chain = newArrayList
+		} else {
+			chain = newArrayList(cachedFullContainmentChainOf( owner as NamedElement ))
+		}
+		chain.add( element )
+		chain
+	}
+	cachedFullContainmentChainOf(NamedElement element) {
+	}
+
+	static def cachedFullContainmentChain(NamedElement element) {
+		INSTANCE.cachedFullContainmentChainOf(element)
+	}
+
+}