blob: 98b83f022c5cc7ee0d895ef7830f6200f26211bd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 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:
* CEA LIST - initial API and implementation
*******************************************************************************/
package org.eclipse.papyrus.designer.languages.c.codegen.transformation;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.ToolFactory;
import org.eclipse.cdt.core.formatter.CodeFormatter;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.papyrus.designer.languages.c.codegen.Activator;
import org.eclipse.papyrus.designer.languages.c.codegen.header.classHeaderScript;
import org.eclipse.papyrus.designer.languages.c.codegen.module.classModuleScript;
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.common.base.ModelElementsCreator;
import org.eclipse.papyrus.designer.languages.common.base.file.FileSystemAccessFactory;
import org.eclipse.papyrus.designer.languages.common.profile.Codegen.NoCodeGen;
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.CppRoot;
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.ManualGeneration;
import org.eclipse.papyrus.designer.languages.cpp.profile.C_Cpp.Template;
import org.eclipse.papyrus.infra.tools.file.IPFileSystemAccess;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.Namespace;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.PrimitiveType;
import org.eclipse.uml2.uml.Relationship;
import org.eclipse.uml2.uml.Signal;
import org.eclipse.uml2.uml.SignalEvent;
import org.eclipse.uml2.uml.Usage;
import org.eclipse.uml2.uml.util.UMLUtil;
/**
* Main class of code generator
*/
public class CModelElementsCreator extends ModelElementsCreator {
private static final String C_LANG = "C"; //$NON-NLS-1$
protected String sourceFolder;
/**
* Constructor.
*
* @param project
* the project in which the generated code should be placed
*/
public CModelElementsCreator(IProject project) {
this(FileSystemAccessFactory.create(project), null);
}
/**
* Constructor, allows for non-standard commentHeader
*
* @param project
* the project in which the generated code should be placed
* @param commentHeader
* Custom prefix for each generated file
*/
public CModelElementsCreator(IProject project, String commentHeader) {
this(FileSystemAccessFactory.create(project), commentHeader);
}
/**
* Constructor. Pass caller defined file system access and commentHeader
*
* @param fileSystemAccess
* the file-system access used to write generated code
* @param commentHeader
* commentHeader. If null, take from preferences
*/
public CModelElementsCreator(IPFileSystemAccess fileSystemAccess, String commentHeader) {
super(fileSystemAccess, new CppLocationStrategy(), C_LANG);
this.commentHeader = (commentHeader != null) ?
commentHeader : CCodeGenUtils.getCommentHeader();
hExt = CCodeGenUtils.getHeaderSuffix();
cExt = CCodeGenUtils.getBodySuffix();
sourceFolder = null;
}
protected String hExt;
protected String cExt;
protected String commentHeader;
/**
* Creates the files corresponding to the class. For a "simple" class
* generates 2 headers (one for the privates concrete operations and one for
* the attributes, public operations and virtual / abstract operations and
* one body file.
*
* @param folder
* @param classifier
* @throws CoreException
*/
@Override
protected void createPackageableElementFile(PackageableElement element, IProgressMonitor monitor) {
if (sourceFolder == null) {
sourceFolder = GenUtils.getSourceFolder(element);
}
if (element instanceof Package) {
// generatePkg((Package) element);
}
else if ((element instanceof PrimitiveType) || (element instanceof Enumeration) || (element instanceof Usage)) {
// do nothing, included in package
}
else if (element instanceof Classifier) {
generateClassifier((Classifier) element);
}
else if (element instanceof Relationship) {
// no code generation for relationships
}
else if (element instanceof Signal) {
// TODO: not supported, but do nothing
}
else if (element instanceof SignalEvent) {
// TODO: not supported, but do nothing
}
else {
Activator.log.debug("C_LANG code generator: unsupported model element " + element); //$NON-NLS-1$
}
}
/**
* Creates the files corresponding to the class. For a "simple" class
* generates 2 headers (one for the privates concrete operations and one for
* the attributes, public operations and virtual / abstract operations and
* one body file.
*
* @param folder
* @param classifier
* @throws CoreException
*/
protected void generateClassifier(Classifier classifier) {
String dot = "."; //$NON-NLS-1$
String LF = "\n"; //$NON-NLS-1$
final String classHeaderFileName = locStrategy.getFileName(classifier) + dot + hExt;
final String classBodyFileName = locStrategy.getFileName(classifier) + dot + cExt;
// treat case of manual code generation
if(GenUtils.hasStereotype(classifier, ManualGeneration.class)) {
ManualGeneration mg = UMLUtil.getStereotypeApplication(classifier, ManualGeneration.class);
Include cppInclude = UMLUtil.getStereotypeApplication(classifier, Include.class);
String fileContent = commentHeader + cppInclude.getHeader();
generateFile(classHeaderFileName, fileContent);
String manualURI = "TODO"; // fileContent = AcceleoDriver.evaluateURI(new URI(CppPackageHeader)), classifier); //$NON-NLS-1$
// fileContent = commentHeader + cppInclude.getPreBody() + GenericGenUtils.NL + manualURI + GenericGenUtils.NL + cppInclude.getBody();
fileContent = commentHeader + cppInclude.getPreBody() + LF + manualURI + LF + cppInclude.getBody();
String ext = GenUtils.maskNull(mg.getExtensionBody());
if(ext.length() == 0) {
ext = cExt;
}
generateFile(classBodyFileName, fileContent);
}
// Only generate when no CppNoCodeGen stereotype is applied to the class
else if((!GenUtils.hasStereotype(classifier, NoCodeGen.class)) &&
(!GenUtils.hasStereotype(classifier, External.class)) &&
(!GenUtils.hasStereotype(classifier, Template.class))) {
// Header file generation
String fileContent = commentHeader + classHeaderScript.classHeaderScript((Class) classifier);
generateFile(classHeaderFileName, fileContent);
// Create class body
if(classifier instanceof Class) {
fileContent = commentHeader + classModuleScript.classModuleScript((Class) classifier);
generateFile(classBodyFileName, fileContent);
}
}
}
protected void generateFile(String fileName, String content) {
fileSystemAccess.generateFile(sourceFolder + fileName, format(content));
}
/**
* Apply the user's currently selected formatting options to the input content. Return the
* input String in case of error.
*/
protected String format(String content) {
// do nothing if the CDT plugin is not loaded
if (Platform.getBundle(CCorePlugin.PLUGIN_ID) == null)
return content;
CodeFormatter codeFormatter = ToolFactory.createCodeFormatter(null);
IDocument doc = new Document(content);
TextEdit edit = codeFormatter.format(CodeFormatter.K_TRANSLATION_UNIT, doc.get(), 0, doc.get().length(), 0, null);
if (edit == null) {
Activator.log.debug(Messages.CModelElementsCreator_CanNotFormatContent);
return content;
}
try {
edit.apply(doc);
return doc.get();
} catch (MalformedTreeException e) {
Activator.log.error(e);
} catch (BadLocationException e) {
Activator.log.error(e);
}
return content;
}
protected void createPackageFiles(IContainer packageContainer, IProgressMonitor monitor, Package pkg) throws CoreException {
// Creates the header for the package.
// String fileContent = commentHeader + AcceleoDriver.evaluateURI(CppPackageHeader, pkg);
// createFile(packageContainer, "Pkg_" + pkg.getName() + "." + hppExt, fileContent, true);
}
protected boolean isRoot(Namespace ns) {
return GenUtils.hasStereotype(ns, CppRoot.class);
}
protected boolean noCodeGen(Element element) {
return GenUtils.hasStereotype(element, NoCodeGen.class);
}
}