Bug 538475 - [Designer] [C Generator] Includes of dependencies are not
generated
- Generate required classifiers
- Generate includes and declares of required classifiers
- Fix generation of includes in header and body
Conflicts:
languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/module/classModuleScript.xtend
Change-Id: Ia5908ea7c172e5424b7a0cdc732f680c38528777
Signed-off-by: Shuai Li <shuai.li@cea.fr>
diff --git a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen.ui/src/org/eclipse/papyrus/designer/languages/c/codegen/ui/handlers/GenerateCodeHandler.java b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen.ui/src/org/eclipse/papyrus/designer/languages/c/codegen/ui/handlers/GenerateCodeHandler.java
index 7a574d6..20d52a4 100644
--- a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen.ui/src/org/eclipse/papyrus/designer/languages/c/codegen/ui/handlers/GenerateCodeHandler.java
+++ b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen.ui/src/org/eclipse/papyrus/designer/languages/c/codegen/ui/handlers/GenerateCodeHandler.java
@@ -23,6 +23,7 @@
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.papyrus.designer.languages.c.codegen.transformation.CModelElementsCreator;
import org.eclipse.papyrus.designer.languages.c.codegen.utils.LocateCProject;
+import org.eclipse.papyrus.designer.languages.common.base.ClassUtils;
import org.eclipse.papyrus.uml.diagram.common.handlers.CmdHandler;
import org.eclipse.swt.widgets.Display;
import org.eclipse.uml2.uml.Classifier;
@@ -76,16 +77,16 @@
mec.createPackageableElement(pe, null, recurse);
// Eventual refresh is done in createPackageableElement
- /*
+
if (pe instanceof Classifier) {
- EList<Classifier> requiredClassifiers = ClassUtils.includedClassifiers((Classifier) pe);
+ EList<Classifier> requiredClassifiers = ClassUtils.requiredClassifiers((Classifier) pe);
for (Classifier requiredClassifier : requiredClassifiers) {
if (!alreadyHandled.contains(requiredClassifier)) {
generate(mec, requiredClassifier, alreadyHandled, false);
}
}
}
- */
+
// owning package is required by generated code.
Package owningPackage = pe.getNearestPackage();
if ((owningPackage != null) && (owningPackage != pe)) {
diff --git a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/header/classHeaderScript.xtend b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/header/classHeaderScript.xtend
index fe2c9c4..eb1ee97 100644
--- a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/header/classHeaderScript.xtend
+++ b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/header/classHeaderScript.xtend
@@ -31,16 +31,13 @@
class classHeaderScript {
def static classHeaderScript(Class clazz) '''
- // This template is called by the main module file
+ ««« This template is called by the main module file
«clazz.genHeading»
«clazz.genHeadingHeader»
- // Explicit import of the class
- «clazz.genImport»
- «clazz.genInclude»
+ «clazz.genHeaderIncludes»
- // header body
«clazz.classHeaderBody»
«clazz.genEndHeader»
diff --git a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/header/dataTypeHeaderScript.xtend b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/header/dataTypeHeaderScript.xtend
index 4291dc4..08f8b1d 100644
--- a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/header/dataTypeHeaderScript.xtend
+++ b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/header/dataTypeHeaderScript.xtend
@@ -33,7 +33,7 @@
«dataType.genHeadingHeader»
// Explicit import of the class
- «dataType.genImport»
+ «dataType.genHeaderIncludes»
// header body
«dataType.dataTypeHeaderBody»
diff --git a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/lib/importScript.xtend b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/lib/importScript.xtend
index ba824c9..a33dd93 100644
--- a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/lib/importScript.xtend
+++ b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/lib/importScript.xtend
@@ -12,119 +12,253 @@
package org.eclipse.papyrus.designer.languages.c.codegen.lib
import java.util.ArrayList
-import org.eclipse.uml2.uml.Class
-import org.eclipse.uml2.uml.Classifier
-import org.eclipse.uml2.uml.DataType
-import org.eclipse.uml2.uml.Element
-import org.eclipse.uml2.uml.Interface
-import org.eclipse.uml2.uml.NamedElement
-import org.eclipse.uml2.uml.Namespace
-import org.eclipse.uml2.uml.Package
-import org.eclipse.uml2.uml.profile.standard.ModelLibrary
-
-import static extension org.eclipse.papyrus.designer.languages.c.codegen.lib.commonScript.*
-import static extension org.eclipse.papyrus.designer.languages.c.codegen.lib.interfaceScript.*
-import static extension org.eclipse.papyrus.designer.languages.c.codegen.services.UmlCommentServices.*
-import static extension org.eclipse.papyrus.designer.languages.common.base.GenUtils.*
+import java.util.List
+import org.eclipse.emf.common.util.EList
+import org.eclipse.papyrus.designer.languages.c.codegen.preferences.CCodeGenUtils
+import org.eclipse.papyrus.designer.languages.common.base.GenUtils
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.CppRoot
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.ExternLibrary
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.External
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Include
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.NoCodeGen
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Template
+import org.eclipse.uml2.uml.Classifier
+import org.eclipse.uml2.uml.Enumeration
+import org.eclipse.uml2.uml.NamedElement
+import org.eclipse.uml2.uml.Package
+import org.eclipse.uml2.uml.PrimitiveType
+import org.eclipse.uml2.uml.util.UMLUtil
+
+import static extension org.eclipse.papyrus.designer.languages.c.codegen.services.UmlCommentServices.*
+import org.eclipse.papyrus.designer.languages.c.codegen.utils.CClassUtils
class importScript {
- def public static genImport(Classifier classifier) '''
- «classifier.partComment('Import')»
- «classifier.genImportList()» «classifier.genDynamicInstanciationImport()»
- // User imports
- /* "startUserCode" to add imports */
- /* "endUserCode" to add imports */
- '''
- def public static genInclude(NamedElement namedElement) '''
- /* include other files*/
- «IF namedElement.hasStereotype(Include)»
- «var include = namedElement.getApplicableStereotype("C_Cpp::Include")»
- «namedElement.getValue(include, "body")»
- «ENDIF»
- '''
-
- def public static genImportList(Classifier classifier) '''
- «FOR import_ : classifier.getImportList»
- «import_.genRelativeNamedImport(classifier)»
+ def public static genHeaderIncludes(Classifier classifier) '''
+ «classifier.partComment('Includes and declares')»
+ ««« Derived includes from required classifiers that are not pointers
+ // Derived includes
+ «FOR path : CClassAllIncludesHeader(classifier).sort»
+ «includeDirective(path)»
«ENDFOR»
+ // End of Derived includes
+
+ ««« Derived includes from required classifiers that are pointers
+ // Derived declares
+ «FOR path : CClassAllDeclares(classifier).sort»
+ «declareDirective(path)»
+ «ENDFOR»
+ // End of Derived declares
+
+ ««« Includes from <<Include>> stereotype's header attribute
+ «classifier.CIncludeHeader()»
+
+ ««« Includes stdio and stdlib
+ // Std headers
+ «genStdInclude()»
+ // End of Std headers
'''
-
- def public static getImportList(Classifier classifier) {
- classifier.genNamespaceImports + classifier.genOwningPackageImports + classifier.genUsageImports
- }
-
-
- def public static genRelativeNamedImport(Element element) '''
+ def public static genBodyIncludes(Classifier classifier) '''
+ ««« Includes from <<Include>> stereotype's preBody attribute
+ «CIncludePreBody(classifier)»
+ ««« Include self header
+ // Include self header
+ «includeDirective(classifier.name + '.' + CCodeGenUtils.getHeaderSuffix())»
+ ««« Derived includes from required classifiers that are dependencies and pointers
+ // Derived includes
+ «FOR path : CClassAllIncludesBody(classifier).sort»
+ «includeDirective(path)»
+ «ENDFOR»
+ ««« Includes from <<Include>> stereotype's body attribute
+ «CIncludeBody(classifier)»
'''
-
- def public static genRelativeNamedImport(NamedElement namedElement1, NamedElement namedElement2) '''
- «IF (namedElement1.hasStereotypeTree(ModelLibrary))»
- #include <«namedElement1.namespace.genName()».h>
- «ELSE»
- #include "«namedElement2.getRelativePath(namedElement1)»«namedElement1.genName()».h"
- «ENDIF»
- '''
-
- def public static genRelativeNamedImport(Package pkg, NamedElement namedElement) '''
- «IF (pkg.hasStereotypeTree(ModelLibrary))»
- #include <«pkg.genName()».h>
- «ELSE»
- #include "«pkg.getRelativePath(namedElement)»«pkg.genName».h"
- «ENDIF»
- '''
-
-
- def public static genOwningPackageImports(Classifier classifier) {
- classifier.namespace.genNamespaceImports()
- }
-
-
- def public static genNamespaceImports(Namespace namespace) {
- namespace.elementImports.map[it.importedElement]
- }
-
- def public static genUsageImports(Classifier lassifier) {
- return new ArrayList<Classifier>();
- }
-
- def public static genUsageImports(Class clazz) {
- if (clazz.hasStereotypeTree(ModelLibrary)) {
- clazz.getUsedInterfaces()
- }
- else {
- clazz.getUsedInterfaces().map[getInterfaceRealizationClass]
- }
- }
-
- def public static getTypeListOfClassifier(Class clazz) {
- val list = clazz.getAllAttributes.map[type]
- list.addAll(clazz.getAllOperations.map[ownedParameters.map[type]])
- list.addAll(clazz.generals)
- return list
- }
-
-
- def public static getTypeListOfClassifier(Interface intf) {
- val list = intf.ownedAttributes.map[type]
- list.addAll(intf.ownedOperations.map[ownedParameters.map[type]])
- list.addAll(intf.generals)
- return list
- }
-
-
- def public static getTypeListOfClassifier(DataType dataType) {
- val list = dataType.ownedAttributes.map[type]
- list.addAll(dataType.ownedOperations.map[ownedParameters.map[type]])
- list.addAll(dataType.generals)
- return list
- }
-
- // TODO: why do need stdlib in this case?
- def public static genDynamicInstanciationImport(Classifier classifier) '''
+ // TODO: why do need stdlib in this case?
+ // TODO: why do we need this at all?
+ def public static genStdInclude() '''
#include <stdio.h>
#include <stdlib.h>
'''
+
+ static def includeDirective(String path) {
+ if ((path !== null) && (path.length > 0))
+ return '''#include ''' + '"' + path + '"'
+ }
+
+ static def CClassAllIncludesHeader(Classifier clazz) {
+ cClassAllIncludes(clazz, CClassUtils.includedClassifiers(clazz))
+ }
+
+ static def CClassAllIncludesBody(Classifier classifier) {
+ cClassAllIncludes(classifier, CClassUtils.includedImplementationClassifiers(classifier))
+ }
+
+ static def cClassAllIncludes(Classifier classifier, EList<Classifier> list) {
+ var List<String> newList = new ArrayList<String>()
+ for (cl : list) {
+ //var String str = null
+ if (cl != classifier && !GenUtils.hasStereotype(cl, NoCodeGen) || GenUtils.hasStereotype(cl, External)) {
+ if ((cl instanceof Enumeration || cl instanceof PrimitiveType) &&
+ !GenUtils.hasStereotype(cl, External) &&
+ !GenUtils.hasStereotypeTree(cl, ExternLibrary)) {
+ if (cl.owner instanceof Package && cl.owner != classifier.owner) {
+ /*
+ * No additional include is required, if enum and primitive types are in
+ * the same package. The latter is always included.
+ */
+ // TODO how is it done in C compared to C++? Following is from C++ generator.
+ //var includePath = (cl.owner as Package).cOwnerPackageIncludePath
+ //if (!newList.contains(includePath)) newList.add(includePath)
+ } else {
+ // str = null
+ }
+ } else {
+ for (includePath : importScript.cClassIncludes(cl)) {
+ if (!newList.contains(includePath)) newList.add(includePath)
+ }
+ }
+ } else {
+ //str = null
+ }
+ }
+ return newList.filter[str | str != null]
+ }
+
+ static def cOwnerPackageIncludePath(Package pkg) {
+ if ((pkg != null) && (!GenUtils.hasStereotype(pkg, CppRoot))) {
+ return GenUtils.getFullPath(pkg) + '/Pkg_' + pkg.name + '.h'
+ } else {
+ return null
+ }
+ }
+
+ static def cClassIncludes(NamedElement ne) {
+ var List<String> result = new ArrayList<String>()
+ if (GenUtils.hasStereotypeTree(ne, ExternLibrary)) {
+ // If a class is in an external library, use #include
+ // directives defined there
+ result.addAll(GenUtils.getApplicationTree(ne, ExternLibrary).includes)
+ // No individual includes are produced for members
+ // unless the stereotype "External" defines one explicitly
+ if (GenUtils.hasStereotype(ne, External)) {
+ val incPath = includeName(ne)
+ if (incPath !== null) {
+ result.add(incPath)
+ }
+ // else: if unset, assume that no additional include directive is required
+ }
+ } else {
+ result.add(includeName(ne))
+ }
+ return result
+ }
+
+ static def includeName(NamedElement ne) {
+ if (GenUtils.hasStereotypeTree(ne, Template)) {
+ return UMLUtil.getStereotypeApplication(ne, Template).declaration
+ } else {
+ if (GenUtils.hasStereotypeTree(ne, External)) {
+ return UMLUtil.getStereotypeApplication(ne, External).incPath
+ } else {
+ // standard case (no stereotypes are applied)
+ return ne.name + '.' + CCodeGenUtils.getHeaderSuffix()
+ }
+ }
+ }
+
+ static def declareDirective(String path) {
+ if ((path != null) && (path.length > 0)) {
+ return path
+ }
+ }
+
+ static def CClassAllDeclares(Classifier clazz) {
+ importScript.cClassAllDeclares(clazz, CClassUtils.declaredClassifiers(clazz), CClassUtils.includedClassifiers(clazz))
+ }
+
+ static def cClassAllDeclares(Classifier classifier, EList<Classifier> declaredClassifiers, EList<Classifier> includedClassifiers) {
+ var List<String> newList = new ArrayList<String>()
+
+ if (declaredClassifiers != null) {
+ if (includedClassifiers != null) {
+ declaredClassifiers.removeAll(includedClassifiers)
+ }
+
+ for (cl : declaredClassifiers) {
+ if (cl != classifier && !GenUtils.hasStereotype(cl, NoCodeGen) || GenUtils.hasStereotype(cl, External)) {
+ var declaration = "";
+
+ if (!(cl instanceof Enumeration) && !(cl instanceof PrimitiveType)) {
+ declaration = "struct " + cl.name + ";";
+ }
+
+ if (declaration != "") {
+ if (!newList.contains(declaration)) {
+ newList.add(declaration);
+ }
+ }
+ }
+ }
+ }
+
+ return newList.filter[str | str != null]
+ }
+
+ static def CIncludeHeader(NamedElement ne) {
+ if (GenUtils.hasStereotype(ne, Include)) {
+ UMLUtil.getStereotypeApplication(ne, Include)
+ var header = UMLUtil.getStereotypeApplication(ne, Include).header
+ if ((header !== null) && (header.length > 0)) {
+ var includeHeader = constIncludeHeaderStart + GenUtils.cleanCR(header) + '\n' +
+ constIncludeHeaderEnd
+ return includeHeader
+ }
+ }
+ }
+
+ static def constIncludeHeaderStart() '''
+ // Include from Include stereotype (header)
+ '''
+
+ static def constIncludeHeaderEnd() '''
+ // End of Include stereotype (header)
+ '''
+
+ static def CIncludePreBody(NamedElement ne) {
+ if (GenUtils.hasStereotype(ne, Include)) {
+ var String preBody = UMLUtil.getStereotypeApplication(ne, Include).preBody
+ if ((preBody != null) && (preBody.length > 0)) {
+ var includePreBody = constIncludePreBodyStart + GenUtils.cleanCR(preBody) + '\n' +
+ constIncludePreBodyEnd
+ return includePreBody
+ }
+ }
+ }
+
+ static def constIncludePreBodyStart() '''
+ // Include from Include stereotype (preBody)
+ '''
+
+ static def constIncludePreBodyEnd() '''
+ // End of Include from Include stereotype (preBody)
+ '''
+
+ static def CIncludeBody(NamedElement ne) {
+ if (GenUtils.hasStereotype(ne, Include)) {
+ var String body = UMLUtil.getStereotypeApplication(ne, Include).body
+ if ((body != null) && (body.length > 0)) {
+ var includeBody = constIncludeBodyStart + GenUtils.cleanCR(body) + '\n' +
+ constIncludeBodyEnd
+ return includeBody
+ }
+ }
+ }
+
+ static def constIncludeBodyStart() '''
+ // Include from Include stereotype (body)
+ '''
+
+ static def constIncludeBodyEnd() '''
+ // End of Include from Include stereotype (body)
+ '''
}
diff --git a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/module/classModuleScript.xtend b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/module/classModuleScript.xtend
index e0c360d..4d1cdb4 100644
--- a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/module/classModuleScript.xtend
+++ b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/module/classModuleScript.xtend
@@ -11,34 +11,29 @@
package org.eclipse.papyrus.designer.languages.c.codegen.module
+import org.eclipse.papyrus.designer.languages.c.codegen.lib.TransformationUtil
+import org.eclipse.uml2.uml.CallEvent
import org.eclipse.uml2.uml.Class
+import org.eclipse.uml2.uml.FinalState
+import org.eclipse.uml2.uml.SignalEvent
+import org.eclipse.uml2.uml.State
+import org.eclipse.uml2.uml.StateMachine
import org.eclipse.uml2.uml.VisibilityKind
import static extension org.eclipse.papyrus.designer.languages.c.codegen.lib.classScript.*
import static extension org.eclipse.papyrus.designer.languages.c.codegen.lib.commonScript.*
import static extension org.eclipse.papyrus.designer.languages.c.codegen.lib.functionScript.*
+import static extension org.eclipse.papyrus.designer.languages.c.codegen.lib.importScript.*
import static extension org.eclipse.papyrus.designer.languages.c.codegen.lib.variableScript.*
import static extension org.eclipse.papyrus.designer.languages.c.codegen.services.UmlCommentServices.*
-import org.eclipse.uml2.uml.CallEvent
-import org.eclipse.uml2.uml.SignalEvent
-import org.eclipse.uml2.uml.Trigger
-import org.eclipse.uml2.uml.StateMachine
-import org.eclipse.papyrus.designer.languages.c.codegen.lib.TransformationUtil
-import org.eclipse.uml2.uml.State
-import org.eclipse.uml2.uml.FinalState
class classModuleScript {
def static classModuleScript(Class clazz) '''
- // This template is called by the main module file
+ ««« This template is called by the main module file
«clazz.genHeading()»
- // include of the self header
- «clazz.genIncludeSelf()»
-
- // Generate import of class ---------------------------------------------
- /* "startUserCode" to add imports */
- /* "endUserCode" to add imports */
-
+ «clazz.genBodyIncludes»
+
«clazz.genModuleDeclarationBody()»
«clazz.genModuleImplementationBody()»
'''
@@ -125,32 +120,28 @@
«ENDFOR»
«ENDIF»
-
«IF (clazz.classifierBehavior != null && !clazz.ownedBehaviors.filter(StateMachine).isEmpty)»
- «var sm = clazz.ownedBehaviors.filter(StateMachine).head»
- // ----------------------------------Entry Exit and DoActivity Implementations for each state ----------------------------------
- «IF sm.regions.head.subvertices.filter(State).filter[!(it instanceof FinalState)].isEmpty»
- «var states = clazz.ownedBehaviors.filter(StateMachine).head.regions.head.subvertices.filter(State).filter[!(it instanceof FinalState)]»
- «FOR state : states»
- «IF (TransformationUtil.isBehaviorExist(state.entry))»
- «state.genEntryImplementation»
- «ENDIF»
- «IF (TransformationUtil.isBehaviorExist(state.exit))»
- «state.genExitImplementation»
- «ENDIF»
- «IF (TransformationUtil.isBehaviorExist(state.doActivity))»
- «state.genDoActivityImplementation»
- «ENDIF»
- «ENDFOR»
-
- «ENDIF»
- «IF(TransformationUtil.hasTriggerlessTransition(sm))»
- //--------------------process Completion Event for completion transition-------------------//
- «clazz.genProcessCompletionEventFunctionImplementation»
-
- «ENDIF»
-
+ «var sm = clazz.ownedBehaviors.filter(StateMachine).head»
+ // ----------------------------------Entry Exit and DoActivity Implementations for each state ----------------------------------
+ «IF sm.regions.head.subvertices.filter(State).filter[!(it instanceof FinalState)].isEmpty»
+ «var states = clazz.ownedBehaviors.filter(StateMachine).head.regions.head.subvertices.filter(State).filter[!(it instanceof FinalState)]»
+ «FOR state : states»
+ «IF (TransformationUtil.isBehaviorExist(state.entry))»
+ «state.genEntryImplementation»
+ «ENDIF»
+ «IF (TransformationUtil.isBehaviorExist(state.exit))»
+ «state.genExitImplementation»
+ «ENDIF»
+ «IF (TransformationUtil.isBehaviorExist(state.doActivity))»
+ «state.genDoActivityImplementation»
+ «ENDIF»
+ «ENDFOR»
+
+ «ENDIF»
+ «IF(TransformationUtil.hasTriggerlessTransition(sm))»
+ //--------------------process Completion Event for completion transition-------------------//
+ «clazz.genProcessCompletionEventFunctionImplementation»
+ «ENDIF»
«ENDIF»
-
'''
}
diff --git a/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/services/CClassUtils.java b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/services/CClassUtils.java
new file mode 100644
index 0000000..9e4c625
--- /dev/null
+++ b/languages/c/org.eclipse.papyrus.designer.languages.c.codegen/src/org/eclipse/papyrus/designer/languages/c/codegen/services/CClassUtils.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2006 - 2012, 2017 CEA LIST.
+ * 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:
+ * Shuai Li (CEA LIST) <shuai.li@cea.fr> - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.papyrus.designer.languages.c.codegen.services;
+
+import java.util.List;
+
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.UniqueEList;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.papyrus.designer.languages.common.base.GenUtils;
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.ExternLibrary;
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.External;
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Inline;
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.NoCodeGen;
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Ptr;
+import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Ref;
+import org.eclipse.uml2.uml.Classifier;
+import org.eclipse.uml2.uml.Enumeration;
+import org.eclipse.uml2.uml.Interface;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.PrimitiveType;
+import org.eclipse.uml2.uml.util.UMLUtil;
+
+public class CClassUtils {
+ /**
+ * Calculate the list of classifiers that needs to be included in a header file
+ *
+ * @param currentClass
+ * @return
+ */
+ public static EList<Classifier> includedClassifiers(Classifier currentClass) {
+ // Retrieve package used by current package (dependencies)
+ // use a unique list to avoid duplicates
+ EList<Classifier> usedClasses = new UniqueEList<Classifier>();
+
+ // Lists of excluded/included stereotypes
+ EList<Class<? extends EObject>> ptrRefStereotypes = new BasicEList<Class<? extends EObject>>();
+ ptrRefStereotypes.add(Ptr.class);
+ ptrRefStereotypes.add(Ref.class);
+
+ EList<Class<? extends EObject>> noCodeGenInlineStereotypes = new BasicEList<Class<? extends EObject>>();
+ noCodeGenInlineStereotypes.add(NoCodeGen.class);
+ noCodeGenInlineStereotypes.add(Inline.class);
+
+ EList<Class<? extends EObject>> inlineStereotypes = new BasicEList<Class<? extends EObject>>();
+ inlineStereotypes.add(Inline.class);
+
+ EList<Class<? extends EObject>> noCodeGenStereotypes = new BasicEList<Class<? extends EObject>>();
+ noCodeGenStereotypes.add(NoCodeGen.class);
+
+ // class attributes dependencies (non-ptr and non-ref)
+ usedClasses.addAll(GenUtils.getTypesViaAttributes(currentClass, ptrRefStereotypes, null, true, true));
+ addEnumerationsPrimitiveTypesExternalTypes(usedClasses, GenUtils.getTypesViaAttributes(currentClass));
+
+ // class inline operation parameters dependencies (non-ptr and non-ref)
+ usedClasses.addAll(GenUtils.getTypesViaOperations(currentClass, noCodeGenStereotypes, inlineStereotypes, ptrRefStereotypes, null, true));
+ addEnumerationsPrimitiveTypesExternalTypes(usedClasses, GenUtils.getTypesViaOperations(currentClass));
+
+ // inner classifier attribute dependencies (non-ptr and non-ref)
+ usedClasses.addAll(GenUtils.getInnerClassifierTypesViaAttributes(currentClass, ptrRefStereotypes, null, true, true));
+ addEnumerationsPrimitiveTypesExternalTypes(usedClasses, GenUtils.getInnerClassifierTypesViaAttributes(currentClass));
+
+ // inner classifier operation parameters dependencies (non-ptr and non-ref)
+ usedClasses.addAll(GenUtils.getInnerClassifierTypesViaOperations(currentClass, noCodeGenStereotypes, inlineStereotypes, ptrRefStereotypes, null, true));
+ addEnumerationsPrimitiveTypesExternalTypes(usedClasses, GenUtils.getInnerClassifierTypesViaOperations(currentClass));
+
+ // realized interface dependencies
+ if (currentClass instanceof org.eclipse.uml2.uml.Class) {
+ org.eclipse.uml2.uml.Class clazz = (org.eclipse.uml2.uml.Class) currentClass;
+ EList<Interface> implementedInterfaces = clazz.getImplementedInterfaces();
+ usedClasses.addAll(implementedInterfaces);
+ }
+ // dependencies and associations
+ usedClasses.addAll(GenUtils.getTypesViaRelationshipsNoDeps(currentClass));
+
+ // template parameters are declared locally (if owned) and do not correspond to a file
+ // that can be included
+ usedClasses.removeAll(GenUtils.getTemplateParameteredElements(currentClass));
+ return usedClasses;
+ }
+
+ /**
+ * Calculate the list of classifiers that needs to be included in a body file
+ *
+ * @param currentClass
+ * @return
+ */
+ public static EList<Classifier> includedImplementationClassifiers(Classifier currentClass) {
+ // Retrieve package used by current package (dependencies)
+ // use a unique list to avoid duplicates
+ EList<Classifier> usedClasses = new UniqueEList<Classifier>();
+
+ // Include all declared classifiers in header
+ // Make sure to not include classifiers already included in header
+ usedClasses.addAll(declaredClassifiers(currentClass));
+ usedClasses.removeAll(includedClassifiers(currentClass));
+
+ // dependency relationships
+ usedClasses.addAll(GenUtils.getTypesViaDependencies(currentClass));
+
+ // template parameters are declared locally (if owned) and do not correspond to a file
+ // that can be included
+ usedClasses.removeAll(GenUtils.getTemplateParameteredElements(currentClass));
+ return usedClasses;
+ }
+
+ /**
+ * Calculate the list of classifiers that needs to be declared in a header file
+ *
+ * @param currentClass
+ * @return
+ */
+ public static EList<Classifier> declaredClassifiers(Classifier currentClass) {
+ EList<Classifier> usedClasses = new UniqueEList<Classifier>();
+
+ // List of excluded/included stereotypes
+ EList<Class<? extends EObject>> ptrRefStereotypes = new BasicEList<Class<? extends EObject>>();
+ ptrRefStereotypes.add(Ptr.class);
+ ptrRefStereotypes.add(Ref.class);
+
+ EList<Class<? extends EObject>> inlineStereotypes = new BasicEList<Class<? extends EObject>>();
+ inlineStereotypes.add(Inline.class);
+
+ EList<Class<? extends EObject>> noCodeGenStereotypes = new BasicEList<Class<? extends EObject>>();
+ noCodeGenStereotypes.add(NoCodeGen.class);
+
+ // class attributes dependencies (only ptr and ref and shared aggregation)
+ usedClasses.addAll(GenUtils.getTypesViaAttributes(currentClass, null, ptrRefStereotypes, false, false));
+ usedClasses.addAll(GenUtils.getTypesViaSharedAggregationAttributes(currentClass));
+ // operation parameters dependencies
+ usedClasses.addAll(GenUtils.getTypesViaOperations(currentClass));
+ usedClasses.removeAll(GenUtils.getTypesViaOperations(currentClass, noCodeGenStereotypes, inlineStereotypes, ptrRefStereotypes, null, true)); // Remove inline operation parameter types that have been included previously
+ // no-specification opaque behavior dependencies
+ usedClasses.addAll(GenUtils.getTypesViaOpaqueBehaviors(currentClass));
+
+ // inner classifier attribute dependencies (only ptr and ref and shared aggregation)
+ usedClasses.addAll(GenUtils.getInnerClassifierTypesViaAttributes(currentClass, null, ptrRefStereotypes, false, false));
+ usedClasses.addAll(GenUtils.getInnerClassifierTypesViaSharedAggregationAttributes(currentClass));
+ // inner classifier parameters dependencies
+ usedClasses.addAll(GenUtils.getInnerClassifierTypesViaOperations(currentClass));
+ usedClasses.removeAll(GenUtils.getInnerClassifierTypesViaOperations(currentClass, noCodeGenStereotypes, inlineStereotypes, ptrRefStereotypes, null, true)); // Remove inner classifier inline operation parameter types that have been included previously
+ // inner classifier no-specification opaque behavior dependencies
+ usedClasses.addAll(GenUtils.getInnerClassifierTypesViaOpaqueBehaviors(currentClass));
+
+ // TODO inline operation body dependencies: how?
+
+ // template parameters are declared locally (if owned) and do not correspond to a file
+ // that can be included
+ usedClasses.removeAll(GenUtils.getTemplateParameteredElements(currentClass));
+
+ // Remove enumerations and primitive types
+ List<Classifier> enumerationsAndPrimitiveTypes = new UniqueEList<Classifier>();
+ for (Classifier classifier : usedClasses) {
+ if ((classifier instanceof Enumeration) || (classifier instanceof PrimitiveType)) {
+ if (classifier.getOwner() instanceof Package) {
+ enumerationsAndPrimitiveTypes.add(classifier);
+ }
+ }
+ }
+ usedClasses.removeAll(enumerationsAndPrimitiveTypes);
+
+ return usedClasses;
+ }
+
+ public static EList<Classifier> usingClassifiers(Classifier currentClass) {
+ EList<Classifier> usedClasses = new UniqueEList<Classifier>();
+ usedClasses.addAll(includedClassifiers(currentClass));
+ usedClasses.addAll(includedImplementationClassifiers(currentClass));
+ usedClasses.addAll(declaredClassifiers(currentClass));
+
+ EList<Classifier> classesToRemove = new UniqueEList<Classifier>();
+ for (Classifier classifier : usedClasses) {
+ if (classifier.getOwner() instanceof Classifier) {
+ classesToRemove.add(classifier);
+ } else if (!classifier.getModel().equals(currentClass.getModel())) {
+ classesToRemove.add(classifier);
+ } else if (UMLUtil.getStereotypeApplication(classifier, External.class) != null) {
+ classesToRemove.add(classifier);
+ } else if (classifier.getOwner() instanceof Package
+ && UMLUtil.getStereotypeApplication(classifier.getOwner(), ExternLibrary.class) != null) {
+ classesToRemove.add(classifier);
+ }
+ }
+
+ usedClasses.removeAll(classesToRemove);
+
+ return usedClasses;
+ }
+
+ private static void addEnumerationsPrimitiveTypesExternalTypes(List<Classifier> usedClasses, List<Classifier> unfilteredClasses) {
+ if (usedClasses != null && unfilteredClasses != null) {
+ for (Classifier classifier : unfilteredClasses) {
+ if ((classifier instanceof Enumeration) || (classifier instanceof PrimitiveType)) {
+ if (classifier.getOwner() instanceof Package) {
+ usedClasses.add(classifier);
+ }
+ } else if (GenUtils.hasStereotype(classifier, External.class)) {
+ usedClasses.add(classifier);
+ }
+ }
+ }
+
+ }
+}