blob: bf2721350b24c3d59b6d81a9087f840937ac2aeb [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
* Ansgar Radermacher (CEA LIST) - Larger refactoring
*******************************************************************************/
package org.eclipse.papyrus.designer.languages.cpp.reverse.reverse
import java.util.ArrayList
import java.util.List
import java.util.regex.Matcher
import java.util.regex.Pattern
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition
import org.eclipse.cdt.core.dom.ast.IASTNode
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter
import org.eclipse.cdt.core.model.IMethodDeclaration
import org.eclipse.cdt.core.model.IMethodTemplateDeclaration
import org.eclipse.cdt.core.parser.IToken
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Const
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.ConstInit
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Friend
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Inline
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Variadic
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Virtual
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Volatile
import org.eclipse.papyrus.designer.uml.tools.utils.StereotypeUtil
import org.eclipse.uml2.uml.Class
import org.eclipse.uml2.uml.OpaqueBehavior
import org.eclipse.uml2.uml.Operation
import org.eclipse.uml2.uml.ParameterDirectionKind
import org.eclipse.uml2.uml.Type
import org.eclipse.uml2.uml.UMLPackage
import org.eclipse.uml2.uml.profile.standard.Create
import org.eclipse.uml2.uml.profile.standard.Destroy
import org.eclipse.uml2.uml.util.UMLUtil
import static extension org.eclipse.papyrus.designer.languages.cpp.reverse.reverse.ASTUtils.*
import static extension org.eclipse.papyrus.designer.languages.cpp.reverse.reverse.ReverseUtils.*
/**
* functions to create and update methods
*/
class MethodUtils {
/**
* Create a UML operation from a CDT method declaration
*/
static def createMethod(IMethodDeclaration method, Class classifier) {
var IASTFunctionDeclarator declarator = method.declarator
if (declarator !== null) {
val op = classifier.createOwnedOperation(method.elementName, null, null)
op.setXmlID
updateMethod(classifier, op, method)
}
}
/**
* Update an existing operation from a CDT method declaration
*/
static def updateMethod(Class classifier, Operation op, IMethodDeclaration method) {
op.name = method.elementName
StereotypeUtil.unapply(op, Inline)
StereotypeUtil.unapply(op, Friend)
StereotypeUtil.unapply(op, Virtual)
StereotypeUtil.unapply(op, Volatile)
StereotypeUtil.unapply(op, Create)
StereotypeUtil.unapply(op, Destroy)
StereotypeUtil.unapply(op, Const)
op.ownedParameters.clear
var List<String> keywords = method.keywords
var body = method.body
op.visibility = method.visibility.convertVisibility
op.isStatic = method.isStatic
op.applyStereotype(method.inline, Inline)
op.applyStereotype(method.friend, Friend)
op.applyStereotype(method.isVirtual, Virtual)
op.applyStereotype(method.volatile, Volatile)
op.applyStereotype(method.isConst, Const)
if (method.isVirtual) {
if (method.pureVirtual) {
op.isAbstract = true
}
}
op.applyStereotype(method.constructor, Create)
op.applyStereotype(method.destructor, Destroy)
try {
var String signature = method.signature
var Pattern pattern = Pattern.compile("([\\s]*)(\\.\\.\\.)([\\s]*)(\\))");
var Matcher matcher = pattern.matcher(signature);
op.applyStereotype(matcher.find(), Variadic)
} catch (Exception e) {
e.printStackTrace
}
if (method instanceof IMethodTemplateDeclaration) {
for (var i = 0; i < method.templateParameterTypes.size; i++) {
GetOrCreateP1.getOrCreateTemplateParameter(op, method.templateParameterTypes.get(i), keywords.get(i))
}
}
var declSpecifier = method.declSpecifier
var declarator = method.declarator
if (!method.constructor && !method.destructor) {
if (method.returnType !== null) {
var parameterType = op.getParameterTemplateType(method, declSpecifier.qualifiedName)
if (parameterType === null) {
parameterType = declSpecifier.qualifiedName.getUMLType(method)
}
var ret = op.createOwnedParameter("ret", parameterType)
ret.direction = ParameterDirectionKind.RETURN_LITERAL
declarator.analyzeDeclaration(ret.type, ret, Cpp_LangID)
PkgDependencies.createDependency(classifier, ret.type)
if (parameterType !== null && parameterType.name.equals("void") && ret.appliedStereotypes.empty) {
ret.destroy
}
ret.applyStereotype(declSpecifier.isConst, Const)
ret.applyStereotype(declSpecifier.isVolatile, Volatile)
} else {
var ret = op.createOwnedParameter("ret", "void".getUMLType(method))
ret.direction = ParameterDirectionKind.RETURN_LITERAL
declarator.analyzeDeclaration(ret.type, ret, Cpp_LangID)
if (ret.appliedStereotypes.empty) {
ret.destroy
}
}
}
for (param : declarator.parameters) {
var parameterType = op.getParameterTemplateType(method, param.declSpecifier.getCppTypeName())
if (parameterType === null) {
parameterType = param.declSpecifier.getUMLType(method)
}
val opParam = op.createOwnedParameter(param.declarator.name.toString, parameterType)
opParam.applyStereotype(param.declSpecifier.const, Const)
param.declarator.analyzeDeclaration(opParam.type, opParam, Cpp_LangID)
opParam.applyStereotype(param.declSpecifier.volatile, Volatile)
}
if (body !== null) {
if (method.constructor) {
var initStr = method.memberInit
if (!initStr.empty) {
StereotypeUtil.apply(op, ConstInit)
UMLUtil.getStereotypeApplication(op, ConstInit).initialisation = initStr
}
}
var OpaqueBehavior ob = null;
if (op.getMethods().size() == 0) {
ob = classifier.createOwnedBehavior(op.name, UMLPackage.Literals.OPAQUE_BEHAVIOR) as OpaqueBehavior
ob.setSpecification(op)
ob.setIsReentrant(false)
} else {
ob = op.getMethods().get(0) as OpaqueBehavior
if (!ob.getName().equals(op.name)) {
ob.setName(op.name);
}
}
if (ob.getBodies().size() == 0) {
ob.getLanguages().add(Cpp_LangID)
ob.getBodies().add("")
}
for (var i = 0; i < ob.getLanguages().size(); i++) {
if (ob.getLanguages().get(i).equals(Cpp_LangID)) {
if (i < ob.getBodies().size()) {
ob.getBodies().set(i, body)
}
}
}
val IASTNode node = method.findEnclosingNode
if (node instanceof IASTFunctionDefinition) {
// new DependencyAnalysis(op, node, method.translationUnit).analyzeDependencies();
}
}
}
static def Type getParameterTemplateType(Operation op, IMethodDeclaration imethod, String typeName) {
var Type ret = null
if (imethod instanceof IMethodTemplateDeclaration) {
if (!imethod.templateParameterTypes.filter[it.equals(typeName)].empty) {
ret = GetOrCreateP1.getOrCreateTemplateParameter(op, typeName, "class")
}
}
return ret
}
static def List<String> getKeywords(IMethodDeclaration method) {
var node = method.findEnclosingNode
var List<String> keywords = new ArrayList
if (node instanceof ICPPASTTemplateDeclaration) {
for (child : node.children) {
if (child instanceof ICPPASTTemplateParameter) {
var token = child.syntax
var keyword = "class"
while (token !== null) {
if (token.type == IToken.t_typename) {
keyword = "typename"
}
token = token.next
}
keywords.add(keyword)
}
}
}
return keywords
}
static def String getBody(IMethodDeclaration method) {
var IASTFunctionDeclarator declarator = null
var node = method.findEnclosingNode
var String body = null
if (node instanceof ICPPASTFunctionDefinition) {
declarator = (node as ICPPASTFunctionDefinition).declarator
body = BatchReverseFunctionBody.getBody(method.translationUnit, node as ICPPASTFunctionDefinition)
} else if (node instanceof IASTFunctionDeclarator) {
// TODO
}
// TODO
/*if (body === null) {
* if (method.translationUnit.isHeaderUnit) {
* val headerUnitNameNoExtension = method.translationUnit.elementName.substring(0, method.translationUnit.elementName.lastIndexOf('.'))
*
* for (ICContainer container : containers) {
* var children = container.children
* container.children.filter(typeof(ITranslationUnit)).filter[!it.isHeaderUnit].forEach [
* val sourceUnitNameNoExtension = it.elementName.substring(0, it.elementName.lastIndexOf('.'))
* if (sourceUnitNameNoExtension.equals(headerUnitNameNoExtension)) {
* var unit = it
* unit.
* println(unit)
* }
* ]
* }
* }iTu l
}*/
return body
}
}