Version: (using KDE Devel) Compiler: gcc 2.95 OS: Linux Someone wanted C-Hash code generation. I was wondering, with C# becoming more important every day (.NET/MONO), will there (or is there already) support for C# code generation ?
*** Bug 65185 has been marked as a duplicate of this bug. ***
Please give a reference/URL to C# standard definition. A coder needs this information to start with a simple generator which can be enhanced later. I already have a list of reserved keywords but no information about syntax and so on.
Heiko Nardmann <heiko.nardmann@onlinehome.de> [040818 11:46]: > Please give a reference/URL to C# standard definition. A coder needs this > information to start with a simple generator which can be enhanced later. > I already have a list of reserved keywords but no information about syntax > and so on. As you are a German reader, I like to point to: http://www.galileocomputing.de/openbook/csharp/ Also, I can test the patches, if they produce correct C# code. Sebastian
Heiko Nardmann <heiko.nardmann@onlinehome.de> [040818 11:46]: > Please give a reference/URL to C# standard definition. A coder needs this > information to start with a simple generator which can be enhanced later. Please take a look at the following page: http://www.wordiq.com/definition/C_Sharp#Standardization There are some links listed directly to the official standard. Sebastian
Sebastian left the dev team so this is wide open.
SVN commit 635308 by okellogg: Add C# code generator by Ferenc Veres, see http://www.geeksoc.org/~jr/umbrello/uml-devel/10058.html Still work in progress - his comments no. 3 to 11 are not yet solved. Perhaps somebody in the know of C# could help out. CCBUG:53368 M +2 -1 ChangeLog M +1 -0 THANKS M +1 -1 umbrello/codegenerators/Makefile.am M +4 -4 umbrello/codegenerators/codegenfactory.cpp A umbrello/codegenerators/csharpwriter.cpp [License: UNKNOWN] A umbrello/codegenerators/csharpwriter.h [License: UNKNOWN] M +4 -4 umbrello/model_utils.cpp M +2 -0 umbrello/uml.cpp M +1 -1 umbrello/umlnamespace.h --- branches/KDE/3.5/kdesdk/umbrello/ChangeLog #635307:635308 @@ -1,6 +1,7 @@ Version 1.5.7 -* Bugs fixed from http://bugs.kde.org: +* Bugs/wishes from http://bugs.kde.org: +* C# Code Generation and export (53368) * %date% and %time% not being parsed (96612) * Relationships for entities do not live outside of the diagram (125146) * Javascript wrong Code Generation (135527) --- branches/KDE/3.5/kdesdk/umbrello/THANKS #635307:635308 @@ -77,6 +77,7 @@ Andrew Sutton <asutton @cs.kent.edu> Tanuj <tagrawal @hss.hns.com> Brian Thomas <brian.thomas @gsfc.nasa.gov> +Ferenc Veres <lion @netngine.hu> Jean Vittor <jean.vittor @wanadoo.fr> Egbert Voigt <Egbert.Voigt @alcatel.de> Stefan Walter <sw @gegenunendlich.de> --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/Makefile.am #635307:635308 @@ -27,7 +27,7 @@ rubycodegenerationpolicy.cpp rubycodegenerationpolicypage.cpp \ rubycodegenerationformbase.ui \ simplecodegenerator.cpp \ - adawriter.cpp aswriter.cpp cppwriter.cpp javawriter.cpp jswriter.cpp \ + adawriter.cpp aswriter.cpp cppwriter.cpp csharpwriter.cpp javawriter.cpp jswriter.cpp \ idlwriter.cpp pascalwriter.cpp perlwriter.cpp php5writer.cpp phpwriter.cpp \ pythonwriter.cpp rubywriter.cpp sqlwriter.cpp tclwriter.cpp xmlschemawriter.cpp \ xmlelementcodeblock.cpp xmlcodecomment.cpp \ --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/codegenfactory.cpp #635307:635308 @@ -34,7 +34,7 @@ #include "adawriter.h" #include "cppwriter.h" -// #include "cswriter.h" // missing in action?!? +#include "csharpwriter.h" #include "idlwriter.h" #include "javawriter.h" #include "pascalwriter.h" @@ -102,9 +102,9 @@ else obj = new CppWriter(); break; - // case Uml::pl_Csharp: - // obj = new CsWriter(); - // break; + case Uml::pl_CSharp: + obj = new CSharpWriter(); + break; case Uml::pl_IDL: obj = new IDLWriter(); break; --- branches/KDE/3.5/kdesdk/umbrello/umbrello/model_utils.cpp #635307:635308 @@ -570,8 +570,8 @@ return "Ada"; case Uml::pl_Cpp: return "C++"; - // case Uml::pl_Csharp: - // return "C#"; + case Uml::pl_CSharp: + return "C#"; case Uml::pl_IDL: return "IDL"; case Uml::pl_Java: @@ -609,8 +609,8 @@ return Uml::pl_Ada; if (str == "C++" || str == "Cpp") // "Cpp" only for bkwd compatibility return Uml::pl_Cpp; - // if (str == "C#") - // return Uml::pl_Csharp; + if (str == "C#") + return Uml::pl_CSharp; if (str == "IDL") return Uml::pl_IDL; if (str == "Java") --- branches/KDE/3.5/kdesdk/umbrello/umbrello/uml.cpp #635307:635308 @@ -457,6 +457,7 @@ m_listDock = createDockWidget( "Model", 0L, 0L, i18n("&Tree View") ); m_listView = new UMLListView(m_listDock ,"LISTVIEW"); + //m_listView->setSorting(-1); m_listView->setDocument(m_doc); m_listView->init(); m_listDock->setWidget(m_listView); @@ -1313,6 +1314,7 @@ QString UMLApp::activeLanguageScopeSeparator() { Uml::Programming_Language pl = getActiveLanguage(); if (pl == Uml::pl_Ada || + pl == Uml::pl_CSharp || pl == Uml::pl_Pascal || pl == Uml::pl_Java || pl == Uml::pl_JavaScript || --- branches/KDE/3.5/kdesdk/umbrello/umbrello/umlnamespace.h #635307:635308 @@ -308,7 +308,7 @@ pl_ActionScript, pl_Ada, pl_Cpp, - // pl_Csharp, + pl_CSharp, pl_IDL, pl_Java, pl_JavaScript,
Created attachment 19752 [details] Types, namespaces and formatting fixes -ignore own namespace in 'using' -less indent if no namespace -using #region for sections -no newlines in parameter documentation -available namespaces are cut from return, attribute and parameter types -property's m_ private missed datatype Some FIXME's are still in, I think some of them depends on the base system. Contact me in case of problems. :)
SVN commit 635717 by okellogg: Apply attachment 19752 [details] from Ferenc Veres with modification for aggregations and compositions. Ferenc, could you look at lines 281ff. and 307ff.? I don't know C# so I'm not sure about the syntax. CCBUG:53368 CCMAIL:lion@netngine.hu M +126 -82 csharpwriter.cpp M +18 -0 csharpwriter.h
Created attachment 19770 [details] Compositions, Aggregations are generated - compositions and aggregations are generated correctly (not with multiplicity yet) - unspecified role names create UnnamedRoleB_1(2,3,4) I am not sure about & and * usage in parameters of my new functions. I did not work in C++ in the past 7-8 years. :-( Please check them, I'll find a book. :-) Most important bug left: interfaces cause warning of multiple inheritance instead listing as interfaces: class myclass : baseclass, interace1, interface2 Thanks for the cooperation ! :-)
SVN commit 636046 by okellogg: Apply attachment 19770 [details] from Ferenc Veres - without visibilityToText(), we can use Uml::Visibility::toString(). CCBUG:53368 M +84 -122 csharpwriter.cpp M +36 -8 csharpwriter.h --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/csharpwriter.cpp #636045:636046 @@ -223,6 +223,7 @@ UMLAssociationList realizations = c->getRealizations(); UMLAssociation *a; bool isInterface = c->isInterface(); + m_unnamedRoles = 1; cs << m_container_indent << "public "; @@ -261,56 +262,15 @@ //associations if (forceSections() || !aggregations.isEmpty()) { - cs << m_endl << m_container_indent << m_indentation << "#region Aggregations" << m_endl; - for (a = aggregations.first(); a; a = aggregations.next()) { - if (c != a->getObject(Uml::A)) // we need to be at the A side - continue; - cs << m_endl; - //maybe we should parse the string here and take multiplicity into account to decide - //which container to use. - UMLObject *o = a->getObject(Uml::B); - if (o == NULL) { - kError() << "aggregation role B object is NULL" << endl; - continue; - } - QString roleName = cleanName(a->getRoleName(Uml::B)); - if (roleName.isEmpty()) - continue; // CHECK: what should be done if no role name is set? - QString typeName = cleanName(o->getName()); - if (a->getMulti(Uml::B).isEmpty()) { - cs << m_container_indent << m_indentation << "//" << typeName - << " " << roleName << ';' << m_endl; - } else { - cs << m_container_indent << m_indentation << "//" << typeName - << " " << roleName << "Vector = array();" << m_endl; - } - }//end for + cs << m_endl << m_container_indent << m_indentation << "#region Aggregations" << m_endl << m_endl; + writeAssociatedAttributes(aggregations, c, cs); cs << m_endl << m_container_indent << m_indentation << "#endregion" << m_endl; } + //compositions if (forceSections() || !compositions.isEmpty()) { - cs << m_endl << m_container_indent << m_indentation << "#region Compositions" << m_endl; - for (a = compositions.first(); a ; a = compositions.next()) { - if (c != a->getObject(Uml::A)) // we need to be at the A side - continue; - // see comment on Aggregation about multiplicity... - UMLObject *o = a->getObject(Uml::B); - if (o == NULL) { - kError() << "composition role B object is NULL" << endl; - continue; - } - QString roleName = cleanName(a->getRoleName(Uml::B)); - if (roleName.isEmpty()) - continue; // CHECK: what should be done if no role name is set? - QString typeName = cleanName(o->getName()); - if (a->getMulti(Uml::B).isEmpty()) { - cs << m_container_indent << m_indentation << "//" << typeName - << " " << roleName << ';' << m_endl; - } else { - cs << m_container_indent << m_indentation << "//" << typeName - << " " << roleName << "Vector = array();" << m_endl; - } - } + cs << m_endl << m_container_indent << m_indentation << "#region Compositions" << m_endl << m_endl; + writeAssociatedAttributes(compositions, c, cs); cs << m_endl << m_container_indent << m_indentation << "#endregion" << m_endl; } @@ -482,19 +442,7 @@ // method visibility cs << m_container_indent << m_indentation; if (op->getAbstract()) cs << "abstract "; - switch (op->getVisibility()) { - case Uml::Visibility::Public: - cs << "public "; - break; - case Uml::Visibility::Protected: - cs << "protected "; - break; - case Uml::Visibility::Private: - cs << "private "; - break; - default: - break; - } + cs << op->getVisibility().toString() << " "; if (op->getStatic()) cs << "static "; // return type @@ -594,83 +542,97 @@ void CSharpWriter::writeAttributes(UMLAttributeList &atList, QTextStream &cs) { + for (UMLAttribute *at = atList.first(); at ; at = atList.next()) { - bool isStatic = at->getStatic(); - if (forceDoc() || !at->getDoc().isEmpty()) { - cs << m_container_indent << m_indentation << "/// <summary>" << m_endl; - cs << formatDoc(at->getDoc(), m_container_indent + m_indentation + "/// "); - cs << m_container_indent << m_indentation << "/// </summary>" << m_endl; + bool asProperty = true; + if (at->getVisibility() == Uml::Visibility::Private) { + asProperty = false; + } + writeAttribute(at->getDoc(), at->getVisibility(), at->getStatic(), + makeLocalTypeName(at), at->getName(), at->getInitialValue(), asProperty, cs); -/* if (isStatic) cs << m_indentation << " * @static" << m_endl; - switch (at->getVisibility()) { - case Uml::Visibility::Public: - cs << m_indentation << " * @access public" << m_endl; - break; - case Uml::Visibility::Protected: - cs << m_indentation << " * @access protected" << m_endl; - break; - case Uml::Visibility::Private: - cs << m_indentation << " * @access private" << m_endl; - break; - default: - break; - } - */ - // cs << m_indentation << " */" << m_endl; + cs << m_endl; + } // end for + return; +} +void CSharpWriter::writeAssociatedAttributes(UMLAssociationList &associated, UMLClassifier *c, QTextStream &cs) { + + UMLAssociation *a; + for (a = associated.first(); a ; a = associated.next()) { + if (c != a->getObject(Uml::A)) // we need to be at the A side + continue; + + UMLObject *o = a->getObject(Uml::B); + if (o == NULL) { + kError() << "composition role B object is NULL" << endl; + continue; } - cs << m_container_indent << m_indentation; - switch (at->getVisibility()) { - case Uml::Visibility::Public: - cs << "public "; - break; - case Uml::Visibility::Protected: - cs << "protected "; - break; - case Uml::Visibility::Private: - cs << "private "; - break; - default: - break; + // Take name and documentaton from Role, take type name from the referenced object + QString roleName = cleanName(a->getRoleName(Uml::B)); + QString typeName = cleanName(o->getName()); + if (roleName.isEmpty()) { + roleName = QString("UnnamedRoleB_%1").arg(m_unnamedRoles++); } - if (isStatic) cs << "static "; + QString roleDoc = a->getRoleDoc(Uml::B); - //Variable type with/without namespace path - cs << makeLocalTypeName(at) << " "; + //FIXME:maybe we should parse the string here and take multiplicity into account to decide + //which container to use. + if (a->getMulti(Uml::B).isEmpty()) { + writeAttribute(roleDoc, a->getVisibility(Uml::B), false, typeName, roleName, "", ( a->getVisibility(Uml::B) != Uml::Visibility::Private), cs); + } else { + // FIXME:not updated for C# yet + cs << m_container_indent << m_indentation << "//" << typeName + << " " << roleName << "Vector = array();" << m_endl; + } + } +} - cs << cleanName(at->getName()); +void CSharpWriter::writeAttribute(QString doc, Uml::Visibility visibility, bool isStatic, QString typeName, QString name, QString initialValue, bool asProperty, QTextStream &cs) { - // FIXME: may need a GUI switch to not generate as Property? + if (forceDoc() || !doc.isEmpty()) { - // Generate as Property if not private - if (at->getVisibility() != Uml::Visibility::Private) - { - cs << m_endl; - cs << m_container_indent << m_indentation << "{" << m_endl; - cs << m_container_indent << m_indentation << m_indentation << "get" << m_endl; - cs << m_container_indent << m_indentation << m_indentation << "{" << m_endl; - cs << m_container_indent << m_indentation << m_indentation << m_indentation << "return m_" << cleanName(at->getName()) << ";" << m_endl; - cs << m_container_indent << m_indentation << m_indentation << "}" << m_endl; + cs << m_container_indent << m_indentation << "/// <summary>" << m_endl; + cs << formatDoc(doc, m_container_indent + m_indentation + "/// "); + cs << m_container_indent << m_indentation << "/// </summary>" << m_endl; - cs << m_container_indent << m_indentation << m_indentation << "set" << m_endl; - cs << m_container_indent << m_indentation << m_indentation << "{" << m_endl; - cs << m_container_indent << m_indentation << m_indentation << m_indentation << "m_" << cleanName(at->getName()) << " = value;" << m_endl; - cs << m_container_indent << m_indentation << m_indentation << "}" << m_endl; - cs << m_container_indent << m_indentation << "}" << m_endl; - cs << m_container_indent << m_indentation << "private " << makeLocalTypeName(at) << " m_" << cleanName(at->getName()) << ";" << m_endl; - } - else - { - cs << ";" << m_endl; - } + } + cs << m_container_indent << m_indentation; + cs << visibility.toString() << " "; + if (isStatic) cs << "static "; -// if (!at->getInitialValue().isEmpty()) -// cs << " = " << at->getInitialValue(); + //Variable type with/without namespace path + cs << typeName << " "; + cs << cleanName(name); + + // FIXME: may need a GUI switch to not generate as Property? + + // Generate as Property if not private + if (asProperty) + { cs << m_endl; - } // end for - return; + cs << m_container_indent << m_indentation << "{" << m_endl; + cs << m_container_indent << m_indentation << m_indentation << "get" << m_endl; + cs << m_container_indent << m_indentation << m_indentation << "{" << m_endl; + cs << m_container_indent << m_indentation << m_indentation << m_indentation << "return m_" << cleanName(name) << ";" << m_endl; + cs << m_container_indent << m_indentation << m_indentation << "}" << m_endl; + + cs << m_container_indent << m_indentation << m_indentation << "set" << m_endl; + cs << m_container_indent << m_indentation << m_indentation << "{" << m_endl; + cs << m_container_indent << m_indentation << m_indentation << m_indentation << "m_" << cleanName(name) << " = value;" << m_endl; + cs << m_container_indent << m_indentation << m_indentation << "}" << m_endl; + cs << m_container_indent << m_indentation << "}" << m_endl; + cs << m_container_indent << m_indentation << "private "; + if (isStatic) cs << "static "; + cs << typeName << " m_" << cleanName(name); + } + + if (!initialValue.isEmpty()) + cs << " = " << initialValue; + + cs << ";" << m_endl << m_endl; } QString CSharpWriter::makeLocalTypeName(UMLClassifierListItem *cl) { --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/csharpwriter.h #636045:636046 @@ -21,7 +21,9 @@ #include "../umlattributelist.h" #include "../umloperationlist.h" #include "../classifierlistitem.h" +#include "../umlassociationlist.h" + /** * class CSharpWriter is a C# code generator for UMLClassifier objects * Just call writeClass and feed it a UMLClassifier; @@ -70,39 +72,65 @@ * Collection of included namespaces, to skip them from variable types. */ UMLPackageList m_seenIncludes; + + /** + * Counts associations without a role name for giving a default name. + */ + int m_unnamedRoles; /** * write all operations for a given class * * @param c the concept we are generating code for - * @param php output stream for the PHP file + * @param cs output stream */ - void writeOperations(UMLClassifier *c, QTextStream &php); + void writeOperations(UMLClassifier *c, QTextStream &cs); /** * write a list of class operations * * @param classname the name of the class * @param opList the list of operations - * @param php output stream for the PHP file + * @param cs output stream * @param interface indicates if the operation is an interface member */ void writeOperations(const QString &classname, UMLOperationList &opList, - QTextStream &php, + QTextStream &cs, bool interface = false, bool generateErrorStub = false); /** write all the attributes of a class * @param c the class we are generating code for - * @param php output stream for the PHP file + * @param cs output stream */ - void writeAttributes(UMLClassifier *c, QTextStream &php); + void writeAttributes(UMLClassifier *c, QTextStream &cs); /** write a list of class attributes * @param atList the list of attributes - * @param php output stream for the PHP file + * @param cs output stream */ - void writeAttributes(UMLAttributeList &atList, QTextStream &php); + void writeAttributes(UMLAttributeList &atList, QTextStream &cs); + /** + * write attributes from associated objects (compositions, aggregations) + * @param associated list of associated objects + * @param c currently written class, to see association direction + * @param cs output stream + */ + void writeAssociatedAttributes(UMLAssociationList &associated, UMLClassifier *c, QTextStream &cs); + + /** + * write a single attribute to the output stream + * @param doc attribute documentation + * @param visibility attribute visibility + * @param isStatic static attribute + * @param typeName class/type of the attribute + * @param name name of the attribute + * @param initialValue initial value given to the attribute at declaration + * @param asProperty true writes as property (get/set), false writes single line variable + * @param cs output stream + */ + void writeAttribute(QString doc, Uml::Visibility visibility, bool isStatic, QString typeName, QString name, QString initialValue, bool asProperty, QTextStream &cs); + /** find the type in used namespaces, if namespace found return short name, complete otherwise. * * @param at Operation or Attribute to check type
Created attachment 19776 [details] Abstract overrides, interfaces are generated, arrays ok. There could be a lot more to do, but now my 50+ classes (not fully worked out) project compiles when loading to VS2005 from Umbrello. Only ENUMS are missing, I make them manually there. Patch: - Implemented Interfaces' methods are generated as skeleton, including recursions - Inherited abstract methods are generated as skels, recursive. (This may of course create unuwanted results, e.g. unwanted implementation locations in the class hierarchy.) - Including some base 'using System*' commands. The whole thing is so much hardcoded already anyway. :-) (This follows VS defaults.) - Not empty and not "1" multiplications are generated as ArrayList (at least compiles now, some ppl may want to customize to Array(), or [] or whatever. - Fixes in some defitions (baseclass+interfaces,etc). Most importnant: if you don't make enums and illogical or invalid things, the generated code compiles out of the box! Very basic generator, but at least there is something. I can create a list of open issues if somebody interested. (I don't like this hardcoded approach, but it was just a "quick hack" from another generator. I hope it will be useful for some people.) Maintainers, please check my * and &, especially on the 2 recursive functions. :-( That may be important, I'd really hate to scratch out elements from the model while generating! ;-) Best regards, Ferenc
SVN commit 636283 by okellogg: Apply attachment 19776 [details] from Ferenc Veres: > Implemented Interfaces' methods are generated as skeleton, including recursions > Inherited abstract methods are generated as skels, recursive. > Including some base 'using System*' commands. > Not empty and not "1" multiplications are generated as ArrayList > Fixes in some defitions (baseclass+interfaces,etc). > [...] Only ENUMS are missing. Many thanks Ferenc for contributing. > Maintainers, please check my * and &, [...] Look okay to me, although you could pass around lists by value (i.e. you don't really need the pointers.) FEATURE:53368 M +124 -70 csharpwriter.cpp M +25 -4 csharpwriter.h --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/csharpwriter.cpp #636282:636283 @@ -177,6 +177,12 @@ UMLDoc *umldoc = UMLApp::app()->getDocument(); UMLFolder *logicalView = umldoc->getRootFolder(Uml::mt_Logical); + // write generic includes + cs << "using System;" << m_endl; + cs << "using System.Text;" << m_endl; + cs << "using System.Collections;" << m_endl; + cs << "using System.Collections.Generic;" << m_endl << m_endl; + //write includes and namespace UMLPackage *container = c->getUMLPackage(); @@ -221,7 +227,6 @@ UMLAssociationList aggregations = c->getAggregations(); UMLAssociationList compositions = c->getCompositions(); UMLAssociationList realizations = c->getRealizations(); - UMLAssociation *a; bool isInterface = c->isInterface(); m_unnamedRoles = 1; @@ -232,29 +237,40 @@ cs << "interface " << classname; } else { //check if class is abstract and / or has abstract methods - if (c->getAbstract()) + if (c->getAbstract() || c->hasAbstractOps()) cs << "abstract "; + cs << "class " << classname << (superclasses.count() > 0 ? " : ":""); + + // write baseclass, ignore interfaces, write error on multiple inheritance if (superclasses.count() > 0) { - - // C# does not support multiple inheritance so only use the first one and print a warning if more are used - - UMLClassifier *obj = superclasses.first(); - cs << cleanName(obj->getName()); - if (superclasses.count() > 1) - cs << m_indentation << "//WARNING: C# does not support multiple inheritance but there is more than 1 superclass defined in your UML model!"; + UMLClassifier *obj; + int supers = 0; + for (obj = superclasses.first(); obj; obj = superclasses.next()) { + if (!obj->isInterface()) { + if (supers > 0) { + cs << " // AND "; + } + cs << cleanName(obj->getName()); + supers++; + } + } + if (supers > 1) { + cs << m_endl << "//WARNING: C# does not support multiple inheritance but there is more than 1 superclass defined in your UML model!" << m_endl; } - // FIXME: I get no (valid) input here (realizations are not coming?) + } //check for realizations + UMLAssociationList realizations = c->getRealizations(); + UMLAssociation *a; + if (!realizations.isEmpty()) { - int rc = realizations.count(); - int ri = rc; for (a = realizations.first(); a; a = realizations.next()) { - UMLObject *o = a->getObject(Uml::B); - QString typeName = cleanName(o->getName()); - if (ri == rc) - cs << ", "; - cs << typeName << (--rc == 0 ? "" : ", "); + UMLClassifier *real = (UMLClassifier*)a->getObject(Uml::B); + if(real != c) { + // write list of realizations + cs << ", " << real->getName(); + } + } } } @@ -304,7 +320,7 @@ UMLOperationList oppub,opprot,oppriv; bool isInterface = c->isInterface(); - bool generateErrorStub = false; + bool generateErrorStub = true; oppub.setAutoDelete(false); opprot.setAutoDelete(false); @@ -328,58 +344,106 @@ } } - QString classname(cleanName(c->getName())); + // write realizations (recursive) + UMLAssociationList realizations = c->getRealizations(); + if (!isInterface && !realizations.isEmpty()) { + writeRealizationsRecursive(c, &realizations, cs); + } + // write public operations if (forceSections() || !oppub.isEmpty()) { cs << m_endl << m_container_indent << m_indentation << "#region Public methods" << m_endl << m_endl; - writeOperations(classname,oppub,cs,isInterface,generateErrorStub); + writeOperations(oppub,cs,isInterface,false,generateErrorStub); cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl; } // write protected operations if (forceSections() || !opprot.isEmpty()) { cs << m_endl << m_container_indent << m_indentation << "#region Protected methods" << m_endl << m_endl; - writeOperations(classname,opprot,cs,isInterface,generateErrorStub); + writeOperations(opprot,cs,isInterface,false,generateErrorStub); cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl; } // write private operations if (forceSections() || !oppriv.isEmpty()) { cs << m_endl << m_container_indent << m_indentation << "#region Private methods" << m_endl << m_endl; - writeOperations(classname,oppriv,cs,isInterface,generateErrorStub); + writeOperations(oppriv,cs,isInterface,false,generateErrorStub); cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl; } + // write superclasses abstract methods + UMLClassifierList superclasses = c->getSuperClasses(); - // build an oplist for all of the realized operations - UMLOperationList opreal; - opreal.setAutoDelete(false); + if (!isInterface && !c->getAbstract() && !c->hasAbstractOps() + && superclasses.count() > 0) { + writeOverridesRecursive(&superclasses, cs); + } - // go through each of the realizations, taking each op - UMLAssociationList realizations = c->getRealizations(); - UMLAssociation *a; +} - if (!realizations.isEmpty()) { - for (a = realizations.first(); a; a = realizations.next()) { +void CSharpWriter::writeOverridesRecursive(UMLClassifierList *superclasses, QTextStream &cs) { + // oplist for implemented abstract operations + UMLOperationList opabstract; + opabstract.setAutoDelete(false); + UMLClassifier *obj; - // we know its a classifier if its in the list - UMLClassifier *real = (UMLClassifier*)a->getObject(Uml::B); - - UMLOperationList opl(real->getOpList()); + for (obj = superclasses->first(); obj; obj = superclasses->next()) { + if (!obj->isInterface() && obj->hasAbstractOps()) { + // collect abstract ops + UMLOperationList opl(obj->getOpList()); for (UMLOperation *op = opl.first(); op ; op = opl.next()) { - opreal.append(op); + if (op->getAbstract()) { + opabstract.append(op); + } } + + // write abstract implementations + cs << m_endl << m_container_indent << m_indentation << "#region " << obj->getName() << " members" << m_endl << m_endl; + writeOperations(opabstract,cs,false,true,true); + cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl; + + opabstract.clear(); } + // Recurse to parent superclasses + UMLClassifierList superRecursive = obj->getSuperClasses(); + UMLClassifierList *superRecursivePtr =& superRecursive; + if (superRecursivePtr->count() > 0) { + writeOverridesRecursive(superRecursivePtr, cs); + } } +} +void CSharpWriter::writeRealizationsRecursive(UMLClassifier *currentClass, UMLAssociationList *realizations, QTextStream &cs) { - // write out all the realizations operations - writeOperations(classname,opreal,cs,false,true); + UMLAssociation *a; + for (a = realizations->first(); a; a = realizations->next()) { + // we know its a classifier if its in the list + UMLClassifier *real = (UMLClassifier*)a->getObject(Uml::B); + + //FIXME: Interfaces realize themselves without this condition!? + if (real == currentClass) + continue; + + // collect operations of one realization + UMLOperationList opreal = real->getOpList(); + + // write realizations + cs << m_endl << m_container_indent << m_indentation << "#region " << real->getName() << " members" << m_endl << m_endl; + writeOperations(opreal,cs,false,false,true); + cs << m_container_indent << m_indentation << "#endregion" << m_endl << m_endl; + + // Recurse to parent realizations + UMLAssociationList parentReal = real->getRealizations(); + if (!parentReal.isEmpty()) { + writeRealizationsRecursive(real, &parentReal, cs); + } + } } -void CSharpWriter::writeOperations(const QString &/* classname */, UMLOperationList &opList, +void CSharpWriter::writeOperations(UMLOperationList opList, QTextStream &cs, bool isInterface /* = false */, + bool isOverride /* = false */, bool generateErrorStub /* = false */) { for (UMLOperation *op=opList.first(); op ; op=opList.next()) { @@ -394,7 +458,7 @@ } //write method documentation - if (writeDoc) + if (writeDoc && !isOverride) { cs << m_container_indent << m_indentation << "/// <summary>" << m_endl; cs << formatDoc(op->getDoc(), m_container_indent + m_indentation + "/// "); @@ -418,32 +482,22 @@ } cs << "</returns>" << m_endl; - /* not used in C# - if (op->getAbstract()) cs << m_indentation << " * @abstract" << m_endl; - if (op->getStatic()) cs << m_indentation << " * @static" << m_endl; - - switch (op->getVisibility()) { - case Uml::Visibility::Public: - cs << m_indentation << " * @access public" << m_endl; - break; - case Uml::Visibility::Protected: - cs << m_indentation << " * @access protected" << m_endl; - break; - case Uml::Visibility::Private: - cs << m_indentation << " * @access private" << m_endl; - break; - default: - break; - } -*/ -// cs <<m_indentation << " */" << m_endl; } // method visibility cs << m_container_indent << m_indentation; - if (op->getAbstract()) cs << "abstract "; - cs << op->getVisibility().toString() << " "; - if (op->getStatic()) cs << "static "; + if (!isInterface) { + if (!isOverride) { + if (op->getAbstract()) cs << "abstract "; + cs << op->getVisibility().toString() << " "; + if (op->getStatic()) cs << "static "; + } + else { + // method overriding an abstract parent + cs << op->getVisibility().toString() << " override "; + if (op->getStatic()) cs << "static "; + } + } // return type if (op->getTypeName() == "") { @@ -472,7 +526,7 @@ cs << ")"; //FIXME: how to control generation of error stub? - if (!isInterface && !op->getAbstract()) { + if (!isInterface && (!op->getAbstract() || isOverride)) { cs << m_endl << m_container_indent << m_indentation << "{" << m_endl; if (generateErrorStub) { cs << m_container_indent << m_indentation << m_indentation; @@ -563,7 +617,7 @@ for (a = associated.first(); a ; a = associated.next()) { if (c != a->getObject(Uml::A)) // we need to be at the A side continue; - + UMLObject *o = a->getObject(Uml::B); if (o == NULL) { kError() << "composition role B object is NULL" << endl; @@ -577,14 +631,14 @@ } QString roleDoc = a->getRoleDoc(Uml::B); - //FIXME:maybe we should parse the string here and take multiplicity into account to decide - //which container to use. - if (a->getMulti(Uml::B).isEmpty()) { + //FIXME:is this simple condition enough? + if (a->getMulti(Uml::B).isEmpty() || a->getMulti(Uml::B) == "1") { + // normal attribute writeAttribute(roleDoc, a->getVisibility(Uml::B), false, typeName, roleName, "", ( a->getVisibility(Uml::B) != Uml::Visibility::Private), cs); } else { - // FIXME:not updated for C# yet - cs << m_container_indent << m_indentation << "//" << typeName - << " " << roleName << "Vector = array();" << m_endl; + // array + roleDoc += "\n(Array of " + typeName + ")"; + writeAttribute(roleDoc, a->getVisibility(Uml::B), false, "ArrayList", roleName, "", ( a->getVisibility(Uml::B) != Uml::Visibility::Private), cs); } } } @@ -631,7 +685,7 @@ if (!initialValue.isEmpty()) cs << " = " << initialValue; - + cs << ";" << m_endl << m_endl; } --- branches/KDE/3.5/kdesdk/umbrello/umbrello/codegenerators/csharpwriter.h #636282:636283 @@ -77,8 +77,19 @@ * Counts associations without a role name for giving a default name. */ int m_unnamedRoles; - + /** + * write realizations of a class and recurse to parent classes + + * @param currentClass class to start with + * @param realizations realizations of this class + * @param cs output stream + */ + void writeRealizationsRecursive(UMLClassifier *currentClass, + UMLAssociationList *realizations, + QTextStream &cs); + + /** * write all operations for a given class * * @param c the concept we are generating code for @@ -89,15 +100,25 @@ /** * write a list of class operations * - * @param classname the name of the class * @param opList the list of operations * @param cs output stream * @param interface indicates if the operation is an interface member + * @param isOverride implementation of an inherited abstract function */ - void writeOperations(const QString &classname, UMLOperationList &opList, + void writeOperations(UMLOperationList opList, QTextStream &cs, - bool interface = false, bool generateErrorStub = false); + bool interface = false, + bool isOverride = false, + bool generateErrorStub = false); + /** + * write superclasses' abstract methods + * + * @param superclasses List of superclasses to start recursing on + * @param cs output stream + */ + void writeOverridesRecursive(UMLClassifierList *superclasses, QTextStream &cs); + /** write all the attributes of a class * @param c the class we are generating code for * @param cs output stream
Git commit a5893a5030a983dfb9efec1bf1dbf34e5b191b8b by Oliver Kellogg. Committed on 19/02/2022 at 16:35. Pushed by okellogg into branch 'master'. umbrello/codegenerators/csharp/csharpwriter.cpp improvements in function defaultDatatypes() - Remove duplicated entries "fixed", "float". - Add entries "nint", "nuint". - For symmetry with Valawriter add single dimension array types for the predefined scalar types. M +22 -2 umbrello/codegenerators/csharp/csharpwriter.cpp https://invent.kde.org/sdk/umbrello/commit/a5893a5030a983dfb9efec1bf1dbf34e5b191b8b