| /******************************************************************************* |
| * 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 |
| } |
| |
| } |