1 /*
2     SPDX-License-Identifier: GPL-2.0-or-later
3 
4     SPDX-FileCopyrightText: 2002 Oliver Kellogg <okellogg@users.sourceforge.net>
5     SPDX-FileCopyrightText: 2003-2021 Umbrello UML Modeller Authors <umbrello-devel@kde.org>
6 */
7 
8 #include "adawriter.h"
9 
10 #include "debug_utils.h"
11 #include "umldoc.h"
12 #include "uml.h"
13 #include "classifier.h"
14 #include "enum.h"
15 #include "classifierlistitem.h"
16 #include "umlclassifierlistitemlist.h"
17 #include "umltemplatelist.h"
18 #include "folder.h"
19 #include "association.h"
20 #include "attribute.h"
21 #include "operation.h"
22 #include "template.h"
23 
24 #include <KLocalizedString>
25 #include <KMessageBox>
26 
27 #include <QFile>
28 #include <QRegExp>
29 #include <QTextStream>
30 
31 const QString AdaWriter::defaultPackageSuffix = QLatin1String("_Holder");
32 
33 /**
34  * Basic Constructor
35  */
AdaWriter()36 AdaWriter::AdaWriter()
37  : SimpleCodeGenerator()
38 {
39     m_indentLevel = 1;  // due to different handling, see finalizeRun()
40 }
41 
42 /**
43  * Empty Destructor
44  */
~AdaWriter()45 AdaWriter::~AdaWriter()
46 {
47 }
48 
49 /**
50  * Returns "Ada".
51  * @return   the programming language identifier
52  */
language() const53 Uml::ProgrammingLanguage::Enum AdaWriter::language() const
54 {
55     return Uml::ProgrammingLanguage::Ada;
56 }
57 
58 /**
59  * Return true if `c' is a tagged type or Ada2005 interface.
60  */
isOOClass(UMLClassifier * c)61 bool AdaWriter::isOOClass(UMLClassifier *c)
62 {
63     UMLObject::ObjectType ot = c->baseType();
64     if (ot == UMLObject::ot_Interface)
65         return true;
66     if (ot == UMLObject::ot_Enum)
67         return false;
68     if (ot != UMLObject::ot_Class) {
69         uDebug() << "unknown object type " << UMLObject::toString(ot);
70         return false;
71     }
72     QString stype = c->stereotype();
73     if (stype == QLatin1String("CORBAConstant") || stype == QLatin1String("CORBATypedef") ||
74             stype == QLatin1String("CORBAStruct") || stype == QLatin1String("CORBAUnion"))
75         return false;
76     // CORBAValue, CORBAInterface, and all empty/unknown stereotypes are
77     // assumed to be object oriented classes.
78     return true;
79 }
80 
81 /**
82  * Returns the class name.
83  */
className(UMLClassifier * c,bool inOwnScope)84 QString AdaWriter::className(UMLClassifier *c, bool inOwnScope)
85 {
86     // If the class has an enclosing package then it is assumed that
87     // the class name is the type name; if the class does not have an
88     // enclosing package then the class name acts as the Ada package
89     // name.
90     QString retval;
91     QString className = cleanName(c->name());
92     UMLPackage *umlPkg = c->umlPackage();
93     if (umlPkg == UMLApp::app()->document()->rootFolder(Uml::ModelType::Logical)) {
94         if (! inOwnScope)
95             retval = className + QLatin1Char('.');
96         retval.append(QLatin1String("Object"));
97     } else {
98         if (! inOwnScope)
99             retval = umlPkg->fullyQualifiedName(QLatin1String(".")) + QLatin1Char('.');
100         retval.append(className);
101     }
102     return retval;
103 }
104 
105 /**
106  * Returns the package name.
107  */
packageName(UMLPackage * p)108 QString AdaWriter::packageName(UMLPackage *p)
109 {
110     // If the class has an enclosing package then it is assumed that
111     // the class name is the type name; if the class does not have an
112     // enclosing package then the class name acts as the Ada package
113     // name.
114     UMLPackage *umlPkg = p->umlPackage();
115     QString className = cleanName(p->name());
116     QString retval;
117 
118     if (umlPkg == UMLApp::app()->document()->rootFolder(Uml::ModelType::Logical))
119         umlPkg = 0;
120 
121     UMLClassifier *c = p->asUMLClassifier();
122     if (umlPkg == 0) {
123         retval = className;
124         if (c == 0 || !isOOClass(c))
125             retval.append(defaultPackageSuffix);
126     } else {
127         retval = umlPkg->fullyQualifiedName(QLatin1String("."));
128     }
129     return retval;
130 }
131 
132 /**
133  * Compute the type and role name from the given association.
134  *
135  * @param c         The UMLClassifier for which code is being generated.
136  * @param a         The UMLAssociation to analyze.
137  * @param typeName  Return value: type name.
138  * @param roleName  Return value: role name.
139  */
computeAssocTypeAndRole(UMLClassifier * c,UMLAssociation * a,QString & typeName,QString & roleName)140 void AdaWriter::computeAssocTypeAndRole(UMLClassifier *c,
141                                         UMLAssociation *a,
142                                         QString& typeName, QString& roleName)
143 {
144     UMLClassifier* assocEnd = a->getObject(Uml::RoleType::B)->asUMLClassifier();
145     if (assocEnd == 0)
146         return;
147     const Uml::AssociationType::Enum assocType = a->getAssocType();
148     if (assocType != Uml::AssociationType::Aggregation && assocType != Uml::AssociationType::Composition)
149         return;
150     const QString multi = a->getMultiplicity(Uml::RoleType::B);
151     bool hasNonUnityMultiplicity = (!multi.isEmpty() && multi != QLatin1String("1"));
152     hasNonUnityMultiplicity &= !multi.contains(QRegExp(QLatin1String("^1 *\\.\\. *1$")));
153     roleName = cleanName(a->getRoleName(Uml::RoleType::B));
154     if (roleName.isEmpty())
155         roleName = cleanName(a->name());
156     if (roleName.isEmpty()) {
157         QString artificialName = cleanName(assocEnd->name());
158         if (hasNonUnityMultiplicity) {
159             roleName = artificialName;
160             roleName.append(QLatin1String("_Vector"));
161         } else {
162             roleName = QLatin1String("M_");
163             roleName.append(artificialName);
164         }
165     }
166     typeName = className(assocEnd, (assocEnd == c));
167     if (hasNonUnityMultiplicity)
168         typeName.append(QLatin1String("_Array_Ptr"));
169     else if (assocType == Uml::AssociationType::Aggregation)
170         typeName.append(QLatin1String("_Ptr"));
171 }
172 
declareClass(UMLClassifier * c,QTextStream & ada)173 void AdaWriter::declareClass(UMLClassifier *c, QTextStream &ada)
174 {
175     UMLClassifierList superclasses = c->getSuperClasses();
176     UMLClassifier *firstSuperClass = 0;
177     if (!superclasses.isEmpty()) {
178         foreach (UMLClassifier* super, superclasses) {
179             if (!super->isInterface()) {
180                 firstSuperClass = super;
181                 break;
182             }
183         }
184         if (firstSuperClass == 0)
185             firstSuperClass = superclasses.first();
186     }
187     const QString name = className(c);
188     ada << indent() << "type " << name << " is ";
189     if (c->isAbstract())
190         ada << "abstract ";
191     if (superclasses.isEmpty()) {
192         ada << "tagged ";
193     } else {
194         ada << "new " << className(firstSuperClass, false);
195         foreach (UMLClassifier* super, superclasses) {
196             if (super->isInterface() && super != firstSuperClass)
197                 ada << " and " << className(super, false);
198         }
199         ada << " with ";
200     }
201 }
202 
203 /**
204  * Call this method to generate Ada code for a UMLClassifier.
205  * @param c the class to generate code for
206  */
writeClass(UMLClassifier * c)207 void AdaWriter::writeClass(UMLClassifier *c)
208 {
209     if (!c) {
210         uDebug() << "Cannot write class of NULL concept!";
211         return;
212     }
213     if (m_classesGenerated.contains(c))
214         return;
215 
216     const bool isClass = !c->isInterface();
217     QString classname = cleanName(c->name());
218     QString pkg = packageName(c);
219     QString fileName = pkg.toLower();
220     fileName.replace(QLatin1Char('.'), QLatin1Char('-'));
221 
222     //find an appropriate name for our file
223     fileName = overwritableName(c, fileName, QLatin1String(".ads"));
224     if (fileName.isEmpty()) {
225         emit codeGenerated(c, false);
226         return;
227     }
228 
229     QFile *file = 0;
230     bool isNewFile = false;
231     PackageFileMap::iterator it = m_pkgsGenerated.find(pkg);
232     if (it != m_pkgsGenerated.end()) {
233         file = it.value();
234     } else {
235         file = new QFile();
236         if (!openFile(*file, fileName)) {
237             emit codeGenerated(c, false);
238             delete file;
239             return;
240         }
241         m_pkgsGenerated[pkg] = file;
242         isNewFile = true;
243     }
244 
245     // Start generating the code.
246 
247     QTextStream ada(file);
248     if (isNewFile) {
249         //try to find a heading file(license, comments, etc)
250         QString str;
251         str = getHeadingFile(QLatin1String(".ads"));
252         if (!str.isEmpty()) {
253             str.replace(QRegExp(QLatin1String("%filename%")), fileName);
254             str.replace(QRegExp(QLatin1String("%filepath%")), file->fileName());
255             ada << str << m_endl;
256         }
257 
258         // Import referenced classes.
259         UMLPackageList imports;
260         findObjectsRelated(c, imports);
261         if (imports.count()) {
262             foreach (UMLPackage* con, imports) {
263                 if (con->isUMLDatatype())
264                     continue;
265                 QString pkgDep = packageName(con);
266                 if (pkgDep != pkg)
267                     ada << "with " << pkgDep << "; " << m_endl;
268             }
269             ada << m_endl;
270         }
271 
272         // Generate generic formals.
273         UMLTemplateList template_params = c->getTemplateList();
274         if (template_params.count()) {
275             ada << indent() << "generic" << m_endl;
276             m_indentLevel++;
277             foreach (UMLTemplate* t, template_params) {
278                 QString formalName = t->name();
279                 QString typeName = t->getTypeName();
280                 if (typeName == QLatin1String("class")) {
281                     ada << indent() << "type " << formalName << " is tagged private;"
282                         << m_endl;
283                 } else {
284                     // Check whether it's a data type.
285                     UMLClassifier *typeObj = t->getType();
286                     if (typeObj == 0) {
287                         uError() << "template_param " << typeName << ": typeObj is NULL";
288                         ada << indent() << "type " << formalName << " is new " << typeName
289                             << " with private;  -- CHECK: codegen error"
290                             << m_endl;
291                     } else if (typeObj->isUMLDatatype()) {
292                         ada << indent() << formalName << " : " << typeName << ";"
293                             << m_endl;
294                     } else {
295                         ada << indent() << "type " << typeName << " is new "
296                             << formalName << " with private;" << m_endl;
297                     }
298                 }
299             }
300             m_indentLevel--;
301         }
302 
303         // Here comes the package proper.
304         ada << "package " << pkg << " is" << m_endl << m_endl;
305     }
306 
307     if (c->baseType() == UMLObject::ot_Enum) {
308         UMLEnum *ue = c->asUMLEnum();
309         UMLClassifierListItemList litList = ue->getFilteredList(UMLObject::ot_EnumLiteral);
310         uint i = 0;
311         ada << indent() << "type " << classname << " is (" << m_endl;
312         m_indentLevel++;
313         foreach (UMLClassifierListItem* lit, litList) {
314             QString enumLiteral = cleanName(lit->name());
315             ada << indent() << enumLiteral;
316             if (++i < (uint)litList.count())
317                 ada << "," << m_endl;
318         }
319         m_indentLevel--;
320         ada << ");" << m_endl << m_endl;
321         ada << "end " << pkg << ";" << m_endl << m_endl;
322         return;
323     }
324     if (! isOOClass(c)) {
325         QString stype = c->stereotype();
326         if (stype == QLatin1String("CORBAConstant")) {
327             ada << indent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl;
328         } else if (stype == QLatin1String("CORBAStruct")) {
329             if (isClass) {
330                 UMLAttributeList atl = c->getAttributeList();
331                 ada << indent() << "type " << classname << " is record" << m_endl;
332                 m_indentLevel++;
333                 foreach (UMLAttribute* at,  atl) {
334                     QString name = cleanName(at->name());
335                     QString typeName = at->getTypeName();
336                     ada << indent() << name << " : " << typeName;
337                     QString initialVal = at->getInitialValue();
338                     if (! initialVal.isEmpty() && ! initialVal.toLatin1().isEmpty())
339                         ada << " := " << initialVal;
340                     ada << ";" << m_endl;
341                 }
342                 m_indentLevel--;
343                 ada << indent() << "end record;" << m_endl << m_endl;
344             }
345         } else if (stype == QLatin1String("CORBAUnion")) {
346             ada << indent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl;
347         } else if (stype == QLatin1String("CORBATypedef")) {
348             ada << indent() << "-- " << stype << " is Not Yet Implemented" << m_endl << m_endl;
349         } else {
350             ada << indent() << "-- " << stype << ": Unknown stereotype" << m_endl << m_endl;
351         }
352         ada << "end " << pkg << ";" << m_endl << m_endl;
353         return;
354     }
355 
356     UMLClassifierList superclasses = c->getSuperClasses();
357     if (!superclasses.isEmpty()) {
358         // Ensure that superclasses in same package are declared before this class.
359         foreach (UMLClassifier* super, superclasses) {
360             if (packageName(super) == pkg && !m_classesGenerated.contains(super)) {
361                 writeClass(super);
362             }
363         }
364     }
365     m_classesGenerated.append(c);
366 
367     // Write class Documentation if non-empty or if force option set.
368     if (forceDoc() || !c->doc().isEmpty()) {
369         ada << "--" << m_endl;
370         ada << "-- class " << classname << m_endl;
371         ada << formatDoc(c->doc(), QLatin1String("-- "));
372         ada << m_endl;
373     }
374 
375     const QString name = className(c);
376     if (isClass) {
377         declareClass(c, ada);
378         ada << "private;" << m_endl << m_endl;
379     } else {
380         ada << indent() << "type " << name << " is interface";
381         foreach (UMLClassifier* super, superclasses) {
382             if (super->isInterface())
383                 ada << " and " << className(super, false);
384         }
385         ada << ";" << m_endl << m_endl;
386     }
387     ada << indent() << "type " << name << "_Ptr is access all " << name << "'Class;" << m_endl << m_endl;
388     ada << indent() << "type " << name << "_Array is array (Positive range <>) of " << name << "_Ptr;" << m_endl << m_endl;
389     ada << indent() << "type " << name << "_Array_Ptr is access " << name << "_Array;" << m_endl << m_endl;
390 
391     // Generate accessors for public attributes.
392     UMLAttributeList atl;
393     if (isClass) {
394         UMLAttributeList atpub;
395 
396         atl = c->getAttributeList();
397 
398         foreach (UMLAttribute* at, atl) {
399             if (at->visibility() == Uml::Visibility::Public)
400                 atpub.append(at);
401         }
402         if (forceSections() || atpub.count())
403             ada << indent() << "-- Accessors for public attributes:" << m_endl << m_endl;
404 
405         foreach (UMLAttribute* at, atpub) {
406             QString member = cleanName(at->name());
407             ada << indent() << "procedure Set_" << member << " (";
408             if (! at->isStatic())
409                 ada << "Self : access " << name << "; ";
410             ada << "To : " << at->getTypeName() << ");" << m_endl;
411             ada << indent() << "function  Get_" << member;
412             if (! at->isStatic())
413                 ada << " (Self : access " << name << ")";
414             ada << " return " << at->getTypeName() << ";" << m_endl << m_endl;
415         }
416     }
417 
418     // Generate public operations.
419     UMLOperationList opl(c->getOpList());
420     UMLOperationList oppub;
421     foreach (UMLOperation* op, opl) {
422         if (op->visibility() == Uml::Visibility::Public)
423             oppub.append(op);
424     }
425     if (forceSections() || oppub.count())
426         ada << indent() << "-- Public methods:" << m_endl << m_endl;
427 
428     foreach (UMLOperation* op, oppub) {
429         writeOperation(op, ada);
430     }
431 
432     emit codeGenerated(c, true);
433 }
434 
435 /**
436  * Write one operation.
437  * @param op          the class for which we are generating code
438  * @param ada         the stream associated with the output file
439  * @param is_comment  flag for a comment
440  */
writeOperation(UMLOperation * op,QTextStream & ada,bool is_comment)441 void AdaWriter::writeOperation(UMLOperation *op, QTextStream &ada, bool is_comment)
442 {
443     UMLAttributeList atl = op->getParmList();
444     QString rettype = op->getTypeName();
445     bool use_procedure = (rettype.isEmpty() || rettype == QLatin1String("void"));
446 
447     ada << indent();
448     if (is_comment)
449         ada << "-- ";
450     if (use_procedure)
451         ada << "procedure ";
452     else
453         ada << "function ";
454     ada << cleanName(op->name()) << " ";
455     if (! (op->isStatic() && atl.count() == 0))
456         ada << "(";
457     UMLClassifier *parentClassifier = op->umlParent()->asUMLClassifier();
458     if (! op->isStatic()) {
459         ada << "Self : access " << className(parentClassifier);
460         if (atl.count())
461             ada << ";" << m_endl;
462     }
463     if (atl.count()) {
464         uint i = 0;
465         m_indentLevel++;
466         foreach (UMLAttribute* at, atl) {
467             ada << indent();
468             if (is_comment)
469                 ada << "-- ";
470             ada << cleanName(at->name()) << " : ";
471             Uml::ParameterDirection::Enum pk = at->getParmKind();
472             if (pk == Uml::ParameterDirection::Out)
473                 ada << "out ";
474             else if (pk == Uml::ParameterDirection::InOut)
475                 ada << "in out ";
476             else
477                 ada << "in ";
478             ada << at->getTypeName();
479             if (! at->getInitialValue().isEmpty())
480                 ada << " := " << at->getInitialValue();
481             if (++i < (uint)atl.count()) //FIXME gcc warning
482                 ada << ";" << m_endl;
483         }
484         m_indentLevel--;
485     }
486     if (! (op->isStatic() && atl.count() == 0))
487         ada << ")";
488     if (! use_procedure)
489         ada << " return " << rettype;
490     if (op->isAbstract())
491         ada << " is abstract";
492     ada << ";" << m_endl << m_endl;
493 }
494 
495 /**
496  * Returns the default datatypes.
497  */
defaultDatatypes() const498 QStringList AdaWriter::defaultDatatypes() const
499 {
500     QStringList l;
501     l.append(QLatin1String("Boolean"));
502     l.append(QLatin1String("Character"));
503     l.append(QLatin1String("Positive"));
504     l.append(QLatin1String("Natural"));
505     l.append(QLatin1String("Integer"));
506     l.append(QLatin1String("Short_Integer"));
507     l.append(QLatin1String("Long_Integer"));
508     l.append(QLatin1String("Float"));
509     l.append(QLatin1String("Long_Float"));
510     l.append(QLatin1String("Duration"));
511     l.append(QLatin1String("String"));
512     return l;
513 }
514 
515 /**
516  * Check whether the given string is a reserved word for the
517  * language of this code generator
518  *
519  * @param rPossiblyReservedKeyword  The string to check.
520  */
isReservedKeyword(const QString & rPossiblyReservedKeyword)521 bool AdaWriter::isReservedKeyword(const QString & rPossiblyReservedKeyword)
522 {
523     const QStringList keywords = reservedKeywords();
524 
525     QStringList::ConstIterator it;
526     for (it = keywords.begin(); it != keywords.end(); ++it) {
527         if ((*it).toLower() == rPossiblyReservedKeyword.toLower()) {
528             return true;
529         }
530     }
531     return false;
532 }
533 
534 /**
535  * Get list of reserved keywords.
536  * @return   the list of reserved keywords
537  */
reservedKeywords() const538 QStringList AdaWriter::reservedKeywords() const
539 {
540     static QStringList keywords;
541 
542     if (keywords.isEmpty()) {
543         keywords.append(QLatin1String("abort"));
544         keywords.append(QLatin1String("abs"));
545         keywords.append(QLatin1String("abstract"));
546         keywords.append(QLatin1String("accept"));
547         keywords.append(QLatin1String("access"));
548         keywords.append(QLatin1String("aliased"));
549         keywords.append(QLatin1String("all"));
550         keywords.append(QLatin1String("and"));
551         keywords.append(QLatin1String("Argument_Error"));
552         keywords.append(QLatin1String("array"));
553         keywords.append(QLatin1String("Assert_Failure"));
554         keywords.append(QLatin1String("at"));
555         keywords.append(QLatin1String("begin"));
556         keywords.append(QLatin1String("body"));
557         keywords.append(QLatin1String("Boolean"));
558         keywords.append(QLatin1String("case"));
559         keywords.append(QLatin1String("Character"));
560         keywords.append(QLatin1String("constant"));
561         keywords.append(QLatin1String("Constraint_Error"));
562         keywords.append(QLatin1String("Conversion_Error"));
563         keywords.append(QLatin1String("Data_Error"));
564         keywords.append(QLatin1String("declare"));
565         keywords.append(QLatin1String("delay"));
566         keywords.append(QLatin1String("delta"));
567         keywords.append(QLatin1String("Dereference_Error"));
568         keywords.append(QLatin1String("Device_Error"));
569         keywords.append(QLatin1String("digits"));
570         keywords.append(QLatin1String("do"));
571         keywords.append(QLatin1String("Duration"));
572         keywords.append(QLatin1String("else"));
573         keywords.append(QLatin1String("elsif"));
574         keywords.append(QLatin1String("end"));
575         keywords.append(QLatin1String("End_Error"));
576         keywords.append(QLatin1String("entry"));
577         keywords.append(QLatin1String("exception"));
578         keywords.append(QLatin1String("exit"));
579         keywords.append(QLatin1String("false"));
580         keywords.append(QLatin1String("Float"));
581         keywords.append(QLatin1String("for"));
582         keywords.append(QLatin1String("function"));
583         keywords.append(QLatin1String("generic"));
584         keywords.append(QLatin1String("goto"));
585         keywords.append(QLatin1String("if"));
586         keywords.append(QLatin1String("in"));
587         keywords.append(QLatin1String("Index_Error"));
588         keywords.append(QLatin1String("Integer"));
589         keywords.append(QLatin1String("interface"));
590         keywords.append(QLatin1String("is"));
591         keywords.append(QLatin1String("Layout_Error"));
592         keywords.append(QLatin1String("Length_Error"));
593         keywords.append(QLatin1String("limited"));
594         keywords.append(QLatin1String("Long_Float"));
595         keywords.append(QLatin1String("Long_Integer"));
596         keywords.append(QLatin1String("Long_Long_Float"));
597         keywords.append(QLatin1String("Long_Long_Integer"));
598         keywords.append(QLatin1String("loop"));
599         keywords.append(QLatin1String("mod"));
600         keywords.append(QLatin1String("Mode_Error"));
601         keywords.append(QLatin1String("Name_Error"));
602         keywords.append(QLatin1String("Natural"));
603         keywords.append(QLatin1String("new"));
604         keywords.append(QLatin1String("not"));
605         keywords.append(QLatin1String("null"));
606         keywords.append(QLatin1String("of"));
607         keywords.append(QLatin1String("or"));
608         keywords.append(QLatin1String("others"));
609         keywords.append(QLatin1String("out"));
610         keywords.append(QLatin1String("package"));
611         keywords.append(QLatin1String("Pattern_Error"));
612         keywords.append(QLatin1String("Picture_Error"));
613         keywords.append(QLatin1String("Pointer_Error"));
614         keywords.append(QLatin1String("Positive"));
615         keywords.append(QLatin1String("pragma"));
616         keywords.append(QLatin1String("private"));
617         keywords.append(QLatin1String("procedure"));
618         keywords.append(QLatin1String("Program_Error"));
619         keywords.append(QLatin1String("protected"));
620         keywords.append(QLatin1String("raise"));
621         keywords.append(QLatin1String("range"));
622         keywords.append(QLatin1String("record"));
623         keywords.append(QLatin1String("rem"));
624         keywords.append(QLatin1String("renames"));
625         keywords.append(QLatin1String("requeue"));
626         keywords.append(QLatin1String("return"));
627         keywords.append(QLatin1String("reverse"));
628         keywords.append(QLatin1String("select"));
629         keywords.append(QLatin1String("separate"));
630         keywords.append(QLatin1String("Short_Float"));
631         keywords.append(QLatin1String("Short_Integer"));
632         keywords.append(QLatin1String("Short_Short_Float"));
633         keywords.append(QLatin1String("Short_Short_Integer"));
634         keywords.append(QLatin1String("Status_Error"));
635         keywords.append(QLatin1String("Storage_Error"));
636         keywords.append(QLatin1String("String"));
637         keywords.append(QLatin1String("subtype"));
638         keywords.append(QLatin1String("Tag_Error"));
639         keywords.append(QLatin1String("tagged"));
640         keywords.append(QLatin1String("task"));
641         keywords.append(QLatin1String("Tasking_Error"));
642         keywords.append(QLatin1String("terminate"));
643         keywords.append(QLatin1String("Terminator_Error"));
644         keywords.append(QLatin1String("then"));
645         keywords.append(QLatin1String("Time_Error"));
646         keywords.append(QLatin1String("Translation_Error"));
647         keywords.append(QLatin1String("true"));
648         keywords.append(QLatin1String("type"));
649         keywords.append(QLatin1String("until"));
650         keywords.append(QLatin1String("Update_Error"));
651         keywords.append(QLatin1String("use"));
652         keywords.append(QLatin1String("Use_Error"));
653         keywords.append(QLatin1String("when"));
654         keywords.append(QLatin1String("while"));
655         keywords.append(QLatin1String("Wide_Character"));
656         keywords.append(QLatin1String("Wide_String"));
657         keywords.append(QLatin1String("with"));
658         keywords.append(QLatin1String("xor"));
659     }
660 
661     return keywords;
662 }
663 
finalizeRun()664 void AdaWriter::finalizeRun()
665 {
666     PackageFileMap::iterator end(m_pkgsGenerated.end());
667     for (PackageFileMap::iterator i = m_pkgsGenerated.begin(); i != end; ++i) {
668         QString pkg = i.key();
669         QFile *file = i.value();
670         QTextStream ada(file);
671         ada << m_endl << "private" << m_endl << m_endl;
672         foreach (UMLClassifier* c, m_classesGenerated) {
673             if (packageName(c) != pkg)
674                 continue;
675             bool isClass = !c->isInterface();
676             if (isClass) {
677                 declareClass(c, ada);
678                 ada << "record" << m_endl;
679                 m_indentLevel++;
680 
681                 UMLAssociationList aggregations = c->getAggregations();
682                 UMLAssociationList compositions = c->getCompositions();
683 
684                 if (forceSections() || !aggregations.isEmpty()) {
685                     ada << indent() << "-- Aggregations:" << m_endl;
686                     foreach (UMLAssociation *a, aggregations) {
687                         if (c != a->getObject(Uml::RoleType::A))
688                             continue;
689                         QString typeName, roleName;
690                         computeAssocTypeAndRole(c, a, typeName, roleName);
691                         ada << indent() << roleName << " : " << typeName << ";" << m_endl;
692                     }
693                     ada << m_endl;
694                 }
695                 if (forceSections() || !compositions.isEmpty()) {
696                     ada << indent() << "-- Compositions:" << m_endl;
697                     foreach (UMLAssociation *a, compositions) {
698                         if (c != a->getObject(Uml::RoleType::A))
699                             continue;
700                         QString typeName, roleName;
701                         computeAssocTypeAndRole(c, a, typeName, roleName);
702                         ada << indent() << roleName << " : " << typeName << ";" << m_endl;
703                     }
704                     ada << m_endl;
705                 }
706 
707                 UMLAttributeList atl = c->getAttributeList();
708                 if (forceSections() || atl.count()) {
709                     ada << indent() << "-- Attributes:" << m_endl;
710                     foreach (UMLAttribute* at, atl) {
711                         if (!at || at->isStatic())
712                             continue;
713                         ada << indent() << cleanName(at->name()) << " : "
714                         << at->getTypeName();
715                         if (!at->getInitialValue().isEmpty() && !at->getInitialValue().toLatin1().isEmpty())
716                             ada << " := " << at->getInitialValue();
717                         ada << ";" << m_endl;
718                     }
719                 }
720                 const bool haveAttrs = (atl.count() != 0);
721                 if (aggregations.isEmpty() && compositions.isEmpty() && !haveAttrs)
722                     ada << indent() << "null;" << m_endl;
723                 m_indentLevel--;
724                 ada << indent() << "end record;" << m_endl << m_endl;
725                 if (haveAttrs) {
726                     bool seen_static_attr = false;
727                     foreach (UMLAttribute* at, atl) {
728                         if (! at->isStatic())
729                             continue;
730                         if (! seen_static_attr) {
731                             ada << indent() << "-- Static attributes:" << m_endl;
732                             seen_static_attr = true;
733                         }
734                         ada << indent();
735                         if (at->visibility() == Uml::Visibility::Private)
736                             ada << "-- Private:  ";
737                         ada << cleanName(at->name()) << " : " << at->getTypeName();
738                         if (at && ! at->getInitialValue().isEmpty() && ! at->getInitialValue().toLatin1().isEmpty())
739                             ada << " := " << at->getInitialValue();
740                         ada << ";" << m_endl;
741                     }
742                     if (seen_static_attr)
743                         ada << m_endl;
744                 }
745             }
746             UMLOperationList opl(c->getOpList());
747             // Generate protected operations.
748             UMLOperationList opprot;
749             foreach (UMLOperation* op,  opl) {
750                 if (op->visibility() == Uml::Visibility::Protected)
751                     opprot.append(op);
752             }
753             if (forceSections() || opprot.count())
754                 ada << indent() << "-- Protected methods:" << m_endl << m_endl;
755             foreach (UMLOperation* op, opprot) {
756                 writeOperation(op, ada);
757             }
758 
759             // Generate private operations.
760             // These are currently only generated as comments in the private part
761             // of the spec.
762             // Once umbrello supports the merging of automatically generated and
763             // hand written code sections, private operations should be generated
764             // into the package body.
765             UMLOperationList oppriv;
766             foreach (UMLOperation* op, opl) {
767                 const Uml::Visibility::Enum vis = op->visibility();
768                 if (vis == Uml::Visibility::Private ||
769                     vis == Uml::Visibility::Implementation)
770                 oppriv.append(op);
771             }
772             if (forceSections() || oppriv.count())
773                 ada << indent() << "-- Private methods:" << m_endl << m_endl;
774             foreach (UMLOperation* op, oppriv) {
775                 writeOperation(op, ada, true);
776             }
777         }
778         ada << m_endl << "end " << i.key() << ";" << m_endl;
779         file->close();
780         emit showGeneratedFile(file->fileName());
781         delete file;
782     }
783 }
784 
785 
786