blob: bd4011284094624339362b2c3f9628cdc00778f9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 CEA LIST
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Shuai Li (CEA LIST) <shuai.li@cea.fr> - Initial API and implementation
* Van Cam Pham (CEA LIST) <vancam.pham@cea.fr> - Reverse implementation
*******************************************************************************/
package org.eclipse.papyrus.designer.languages.cpp.reverse.utils
import java.util.ArrayList
import java.util.List
import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration
import org.eclipse.cdt.core.model.ICElement
import org.eclipse.cdt.core.model.IParent
import org.eclipse.cdt.core.model.IStructure
import org.eclipse.cdt.core.model.IStructureTemplate
import org.eclipse.cdt.core.model.ITranslationUnit
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.common.util.UniqueEList
import org.eclipse.papyrus.designer.languages.common.profile.Codegen.NoCodeGen
import org.eclipse.papyrus.designer.languages.cpp.codegen.transformation.CppLocationStrategy
import org.eclipse.papyrus.designer.languages.cpp.library.CppUriConstants
import org.eclipse.papyrus.designer.uml.tools.utils.PackageUtil
import org.eclipse.papyrus.designer.uml.tools.utils.StereotypeUtil
import org.eclipse.uml2.uml.Classifier
import org.eclipse.uml2.uml.Model
import org.eclipse.uml2.uml.NamedElement
import org.eclipse.uml2.uml.Operation
import org.eclipse.uml2.uml.Package
import org.eclipse.uml2.uml.ParameterDirectionKind
import org.eclipse.uml2.uml.Profile
import org.eclipse.uml2.uml.Type
import static extension org.eclipse.papyrus.designer.languages.cpp.reverse.reverse.ReverseUtils.*
import org.eclipse.papyrus.designer.languages.cpp.reverse.reverse.BatchReverseFunctionBody
/**
* Utility methods for round-trip
*
*/
class RoundtripCppUtils {
/**
* Get or create a classifier
* Use for Source sync.
*/
def static Classifier getOrCreateClassifier(IStructure iStructure, ITranslationUnit iTu, String projectName,
Model model) {
var Classifier classifier = null
// var engine = IncQueryEngineSingleton.getEngine(model.eResource.resourceSet)
val arrayNames = iTu.location.toString.split(projectName).last.substring(1).split("/")
val names = new ArrayList<String>
arrayNames.forEach[names.add(it)]
// classifier = RoundtripQuery.instance.getMappedElement(engine).
// getAllValuesOfumlElement(classifier.fileName).filter(typeof(Classifier)).head
if (classifier === null) {
var Package parentPack = iTu.correspondingModel;
if (parentPack.getOwnedType(iStructure.elementName) === null) {
parentPack.createOwnedClass(iStructure.elementName, false)
}
classifier = parentPack.getOwnedType(iStructure.elementName) as Classifier
}
return classifier
}
def static getFileName(NamedElement element) {
val cppLocationStrategy = new CppLocationStrategy
return cppLocationStrategy.getFileName(element)
}
static def getPrimitiveType(String name, Model model) {
var isPrimitive = isPrimitiveCppType(name)
if (isPrimitive) {
// get ansipackage or import to model
var Package ansiPack = PackageUtil.loadPackage(CppUriConstants.ANSIC_LIB_URI, model.eResource.resourceSet)
return name.getTypeFromModel(ansiPack)
}
return null;
}
static def isPrimitiveCppType(String name) {
return !BatchReverseFunctionBody.ansiTypes.filter[it.equals(name)].empty
}
def static Type getTypeFromModel(String name, Package pack) {
if(pack === null) return {
null
}
var ret = pack.getPackagedElement(name)
if (ret === null || !(ret instanceof Type)) {
return null
}
return ret as Type
}
static def applyProfile(Model model, String uri) {
var resource = model.eResource.resourceSet.getResource(URI.createURI(uri), false)
if (resource === null) {
resource = model.eResource.resourceSet.createResource(URI.createURI(uri))
resource.load(null)
}
var profile = resource.contents.filter(typeof(Profile)).head
if (profile !== null && !model.isProfileApplied(profile)) {
model.applyProfile(profile)
}
}
static def Operation findMatchOperation(Classifier classifier, IASTFunctionDeclarator declarator, String[] names, ITranslationUnit iTu) {
var Operation ret = null;
if (classifier !== null && declarator !== null && names !== null && iTu !== null) {
if (names.length == 1) {
// TODO: function not inside any classes
return null;
} else if (names.length > 1) {
var String classifierName = names.get(names.length - 2);
if (!classifier.name.equals(classifierName)) {
return null;
}
var List<String> contextNamespaces = new UniqueEList<String>()
var String qualifiedTypeName = ""
for (i : 0 ..< names.length - 1) {
qualifiedTypeName += names.get(i)
if (i != names.length - 2) {
qualifiedTypeName += "::"
}
}
// TODO: what is done here ..., contextNamespaces are unused
contextNamespaces.add(qualifiedTypeName);
var Type ownerClass = classifierName.getUMLType(iTu);
if (ownerClass instanceof Classifier) {
if (ownerClass != classifier) {
return null;
}
}
}
// Single parameter of type void ==> no parameters
var nParmeters = declarator.children.filter(typeof(IASTParameterDeclaration)).size
val parameterFunctionList = declarator.children.filter(typeof(IASTParameterDeclaration))
if (declarator.children.filter(typeof(IASTParameterDeclaration)).size == 1) {
var parameterNode = declarator.children.filter(typeof(IASTParameterDeclaration)).get(0)
if (parameterNode.declSpecifier !== null) {
var String type = ""
var tokens = parameterNode.declSpecifier.syntax
while(tokens !== null) {
type += tokens.toString
tokens = tokens.next
}
if (type.trim.equals("void")) {
nParmeters = 0
}
}
}
val numberParameter = nParmeters
val functionName = names.get(names.length - 1)
// TODO:check classifier name
var sameNames = classifier.allOperations.filter[it.name.equals(functionName)]
var sameNumberOfParameters = sameNames.filter [
it.ownedParameters.filter[it.direction != ParameterDirectionKind.RETURN_LITERAL].size == numberParameter
]
// compare signatures by parameter type name
for (op : sameNumberOfParameters) {
if (ret === null) {
var isMatch = true
var parameterList = op.ownedParameters.filter[it.direction != ParameterDirectionKind.RETURN_LITERAL]
for (var i = 0; i < numberParameter; i++) {
if (!parameterList.get(i).type.name.equals(
parameterFunctionList.get(i).declSpecifier.cppTypeName)) {
isMatch = false
} else {
if (parameterList.get(i).name === null || parameterList.get(i).name.equals("")) {
var paramName = parameterFunctionList.get(i).declarator.name
if (paramName !== null) {
parameterList.get(i).name = paramName.toString
}
}
}
}
if (isMatch) {
ret = op
}
}
}
}
return ret;
}
private def static String getCppTypeName(IASTDeclSpecifier declarator) {
var String parameterTypeName = ""; // $NON-NLS-1$
try {
var token = declarator.syntax
while (token !== null) {
var String tokenStr = token.toString()
if (tokenStr.equals("*")) { // $NON-NLS-1$
// TODO: check, if this can be called (depending on
// * position with different semantics?)
// isPointer = true;
} else if (tokenStr.equals("&")) { // $NON-NLS-1$
// isRef = true;
} else if (tokenStr.equals("const")) { // $NON-NLS-1$
// do nothing (use isConst() operation of
// parameterType)
// is not part of parameter type
} else if (tokenStr.equals("volatile")) {
// do nothing
} else {
if (parameterTypeName.length() > 0) {
parameterTypeName += " "; // $NON-NLS-1$
}
parameterTypeName += tokenStr;
}
token = token.getNext();
}
} catch (ExpansionOverlapsBoundaryException e) {
}
return parameterTypeName
}
static def List<IStructureTemplate> getAllStructureTemplates(IParent parent) {
var List<IStructureTemplate> ret = new UniqueEList
var ICElement[] childrend = parent.getChildren();
for (var i = 0; i < childrend.length; i++) {
var child = childrend.get(i)
switch (child) {
case child instanceof IStructureTemplate: {
var istructureTemplate = childrend.get(i) as IStructureTemplate
ret.add(istructureTemplate)
}
case child instanceof IParent: {
ret.addAll(getAllStructureTemplates(child as IParent))
}
}
}
return ret
}
public static final String EXTERNAL_PACKAGE_NAME = "external"
static def getOrcreateExternalPackage(Package parentPack, boolean create) {
if (parentPack.getNestedPackage(EXTERNAL_PACKAGE_NAME) === null) {
if (create) {
var createdPack = parentPack.createNestedPackage(EXTERNAL_PACKAGE_NAME)
StereotypeUtil.apply(createdPack, NoCodeGen)
}
}
parentPack.getNestedPackage(EXTERNAL_PACKAGE_NAME)
}
}