Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*
43 generator.cpp
44*/
45#include <qdir.h>
46#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
47#include <qdebug.h>
48#endif
49#include "codemarker.h"
50#include "config.h"
51#include "doc.h"
52#include "editdistance.h"
53#include "generator.h"
54#include "node.h"
55#include "openedlist.h"
56#include "quoter.h"
57#include "separator.h"
58#include "tokenizer.h"
59#include "ditaxmlgenerator.h"
60
61QT_BEGIN_NAMESPACE
62
63QList<Generator *> Generator::generators;
64QMap<QString, QMap<QString, QString> > Generator::fmtLeftMaps;
65QMap<QString, QMap<QString, QString> > Generator::fmtRightMaps;
66QMap<QString, QStringList> Generator::imgFileExts;
67QSet<QString> Generator::outputFormats;
68QStringList Generator::imageFiles;
69QStringList Generator::imageDirs;
70QStringList Generator::exampleDirs;
71QStringList Generator::exampleImgExts;
72QStringList Generator::scriptFiles;
73QStringList Generator::scriptDirs;
74QStringList Generator::styleFiles;
75QStringList Generator::styleDirs;
76QString Generator::outDir;
77QString Generator::project;
78QHash<QString, QString> Generator::outputPrefixes;
79
80QString Generator::sinceTitles[] =
81 {
82 " New Namespaces",
83 " New Classes",
84 " New Member Functions",
85 " New Functions in Namespaces",
86 " New Global Functions",
87 " New Macros",
88 " New Enum Types",
89 " New Typedefs",
90 " New Properties",
91 " New Variables",
92 " New QML Elements",
93 " New QML Properties",
94 " New QML Signals",
95 " New QML Methods",
96 ""
97 };
98
99static void singularPlural(Text& text, const NodeList& nodes)
100{
101 if (nodes.count() == 1)
102 text << " is";
103 else
104 text << " are";
105}
106
107Generator::Generator()
108 : amp("&amp;"),
109 lt("&lt;"),
110 gt("&gt;"),
111 quot("&quot;"),
112 tag("</?@[^>]*>")
113{
114 generators.prepend(this);
115}
116
117Generator::~Generator()
118{
119 generators.removeAll(this);
120}
121
122void Generator::initializeGenerator(const Config & /* config */)
123{
124}
125
126void Generator::terminateGenerator()
127{
128}
129
130void Generator::initialize(const Config &config)
131{
132 outputFormats = config.getStringSet(CONFIG_OUTPUTFORMATS);
133 if (!outputFormats.isEmpty()) {
134 outDir = config.getString(CONFIG_OUTPUTDIR);
135 if (outDir.isEmpty())
136 config.lastLocation().fatal(tr("No output directory specified in configuration file"));
137
138 QDir dirInfo;
139 if (dirInfo.exists(outDir)) {
140 if (!Config::removeDirContents(outDir))
141 config.lastLocation().error(tr("Cannot empty output directory '%1'").arg(outDir));
142 }
143 else {
144 if (!dirInfo.mkpath(outDir))
145 config.lastLocation().fatal(tr("Cannot create output directory '%1'").arg(outDir));
146 }
147
148 if (!dirInfo.mkdir(outDir + "/images"))
149 config.lastLocation().fatal(tr("Cannot create output directory '%1'")
150 .arg(outDir + "/images"));
151 if (!dirInfo.mkdir(outDir + "/images/used-in-examples"))
152 config.lastLocation().fatal(tr("Cannot create output directory '%1'")
153 .arg(outDir + "/images/used-in-examples"));
154 if (!dirInfo.mkdir(outDir + "/scripts"))
155 config.lastLocation().fatal(tr("Cannot create output directory '%1'")
156 .arg(outDir + "/scripts"));
157 if (!dirInfo.mkdir(outDir + "/style"))
158 config.lastLocation().fatal(tr("Cannot create output directory '%1'")
159 .arg(outDir + "/style"));
160 }
161
162 imageFiles = config.getStringList(CONFIG_IMAGES);
163 imageDirs = config.getStringList(CONFIG_IMAGEDIRS);
164 scriptFiles = config.getStringList(CONFIG_SCRIPTS);
165 scriptDirs = config.getStringList(CONFIG_SCRIPTDIRS);
166 styleFiles = config.getStringList(CONFIG_STYLES);
167 styleDirs = config.getStringList(CONFIG_STYLEDIRS);
168 exampleDirs = config.getStringList(CONFIG_EXAMPLEDIRS);
169 exampleImgExts = config.getStringList(CONFIG_EXAMPLES + Config::dot +
170 CONFIG_IMAGEEXTENSIONS);
171
172 QString imagesDotFileExtensions =
173 CONFIG_IMAGES + Config::dot + CONFIG_FILEEXTENSIONS;
174 QSet<QString> formats = config.subVars(imagesDotFileExtensions);
175 QSet<QString>::ConstIterator f = formats.begin();
176 while (f != formats.end()) {
177 imgFileExts[*f] = config.getStringList(imagesDotFileExtensions +
178 Config::dot + *f);
179 ++f;
180 }
181
182 QList<Generator *>::ConstIterator g = generators.begin();
183 while (g != generators.end()) {
184 if (outputFormats.contains((*g)->format())) {
185 (*g)->initializeGenerator(config);
186 QStringList extraImages =
187 config.getStringList(CONFIG_EXTRAIMAGES+Config::dot+(*g)->format());
188 QStringList::ConstIterator e = extraImages.begin();
189 while (e != extraImages.end()) {
190 QString userFriendlyFilePath;
191 QString filePath = Config::findFile(config.lastLocation(),
192 imageFiles,
193 imageDirs,
194 *e,
195 imgFileExts[(*g)->format()],
196 userFriendlyFilePath);
197 if (!filePath.isEmpty())
198 Config::copyFile(config.lastLocation(),
199 filePath,
200 userFriendlyFilePath,
201 (*g)->outputDir() +
202 "/images");
203 ++e;
204 }
205
206 // Documentation template handling
207 QString templateDir = config.getString(
208 (*g)->format() + Config::dot + CONFIG_TEMPLATEDIR);
209
210 if (!templateDir.isEmpty()) {
211 QStringList noExts;
212 QStringList searchDirs = QStringList() << templateDir;
213 QStringList scripts =
214 config.getStringList((*g)->format()+Config::dot+CONFIG_SCRIPTS);
215 e = scripts.begin();
216 while (e != scripts.end()) {
217 QString userFriendlyFilePath;
218 QString filePath = Config::findFile(config.lastLocation(),
219 scriptFiles,
220 searchDirs,
221 *e,
222 noExts,
223 userFriendlyFilePath);
224 if (!filePath.isEmpty())
225 Config::copyFile(config.lastLocation(),
226 filePath,
227 userFriendlyFilePath,
228 (*g)->outputDir() +
229 "/scripts");
230 ++e;
231 }
232
233 QStringList styles =
234 config.getStringList((*g)->format()+Config::dot+CONFIG_STYLESHEETS);
235 e = styles.begin();
236 while (e != styles.end()) {
237 QString userFriendlyFilePath;
238 QString filePath = Config::findFile(config.lastLocation(),
239 styleFiles,
240 searchDirs,
241 *e,
242 noExts,
243 userFriendlyFilePath);
244 if (!filePath.isEmpty())
245 Config::copyFile(config.lastLocation(),
246 filePath,
247 userFriendlyFilePath,
248 (*g)->outputDir() +
249 "/style");
250 ++e;
251 }
252 }
253 }
254 ++g;
255 }
256
257 QRegExp secondParamAndAbove("[\2-\7]");
258 QSet<QString> formattingNames = config.subVars(CONFIG_FORMATTING);
259 QSet<QString>::ConstIterator n = formattingNames.begin();
260 while (n != formattingNames.end()) {
261 QString formattingDotName = CONFIG_FORMATTING + Config::dot + *n;
262
263 QSet<QString> formats = config.subVars(formattingDotName);
264 QSet<QString>::ConstIterator f = formats.begin();
265 while (f != formats.end()) {
266 QString def = config.getString(formattingDotName +
267 Config::dot + *f);
268 if (!def.isEmpty()) {
269 int numParams = Config::numParams(def);
270 int numOccs = def.count("\1");
271
272 if (numParams != 1) {
273 config.lastLocation().warning(tr("Formatting '%1' must "
274 "have exactly one "
275 "parameter (found %2)")
276 .arg(*n).arg(numParams));
277 }
278 else if (numOccs > 1) {
279 config.lastLocation().fatal(tr("Formatting '%1' must "
280 "contain exactly one "
281 "occurrence of '\\1' "
282 "(found %2)")
283 .arg(*n).arg(numOccs));
284 }
285 else {
286 int paramPos = def.indexOf("\1");
287 fmtLeftMaps[*f].insert(*n, def.left(paramPos));
288 fmtRightMaps[*f].insert(*n, def.mid(paramPos + 1));
289 }
290 }
291 ++f;
292 }
293 ++n;
294 }
295
296 project = config.getString(CONFIG_PROJECT);
297
298 QStringList prefixes = config.getStringList(CONFIG_OUTPUTPREFIXES);
299 if (!prefixes.isEmpty()) {
300 foreach (QString prefix, prefixes)
301 outputPrefixes[prefix] = config.getString(
302 CONFIG_OUTPUTPREFIXES + Config::dot + prefix);
303 } else
304 outputPrefixes[QLatin1String("QML")] = QLatin1String("qml-");
305}
306
307void Generator::terminate()
308{
309 QList<Generator *>::ConstIterator g = generators.begin();
310 while (g != generators.end()) {
311 if (outputFormats.contains((*g)->format()))
312 (*g)->terminateGenerator();
313 ++g;
314 }
315
316 fmtLeftMaps.clear();
317 fmtRightMaps.clear();
318 imgFileExts.clear();
319 imageFiles.clear();
320 imageDirs.clear();
321 outDir = "";
322 QmlClassNode::clear();
323}
324
325Generator *Generator::generatorForFormat(const QString& format)
326{
327 QList<Generator *>::ConstIterator g = generators.begin();
328 while (g != generators.end()) {
329 if ((*g)->format() == format)
330 return *g;
331 ++g;
332 }
333 return 0;
334}
335
336void Generator::startText(const Node * /* relative */,
337 CodeMarker * /* marker */)
338{
339}
340
341void Generator::endText(const Node * /* relative */,
342 CodeMarker * /* marker */)
343{
344}
345
346int Generator::generateAtom(const Atom * /* atom */,
347 const Node * /* relative */,
348 CodeMarker * /* marker */)
349{
350 return 0;
351}
352
353void Generator::generateClassLikeNode(const InnerNode * /* classe */,
354 CodeMarker * /* marker */)
355{
356}
357
358void Generator::generateFakeNode(const FakeNode * /* fake */,
359 CodeMarker * /* marker */)
360{
361}
362
363bool Generator::generateText(const Text& text,
364 const Node *relative,
365 CodeMarker *marker)
366{
367 bool result = false;
368 if (text.firstAtom() != 0) {
369 int numAtoms = 0;
370 startText(relative, marker);
371 generateAtomList(text.firstAtom(),
372 relative,
373 marker,
374 true,
375 numAtoms);
376 endText(relative, marker);
377 result = true;
378 }
379 return result;
380}
381
382#ifdef QDOC_QML
383/*!
384 Extract sections of markup text surrounded by \e qmltext
385 and \e endqmltext and output them.
386 */
387bool Generator::generateQmlText(const Text& text,
388 const Node *relative,
389 CodeMarker *marker,
390 const QString& /* qmlName */ )
391{
392 const Atom* atom = text.firstAtom();
393 bool result = false;
394
395 if (atom != 0) {
396 startText(relative, marker);
397 while (atom) {
398 if (atom->type() != Atom::QmlText)
399 atom = atom->next();
400 else {
401 atom = atom->next();
402 while (atom && (atom->type() != Atom::EndQmlText)) {
403 int n = 1 + generateAtom(atom, relative, marker);
404 while (n-- > 0)
405 atom = atom->next();
406 }
407 }
408 }
409 endText(relative, marker);
410 result = true;
411 }
412 return result;
413}
414#endif
415
416void Generator::generateBody(const Node *node, CodeMarker *marker)
417{
418 bool quiet = false;
419
420 if (node->type() == Node::Fake) {
421 const FakeNode *fake = static_cast<const FakeNode *>(node);
422 if (fake->subType() == Node::Example) {
423 generateExampleFiles(fake, marker);
424 }
425 else if ((fake->subType() == Node::File) || (fake->subType() == Node::Image)) {
426 quiet = true;
427 }
428 }
429
430 if (node->doc().isEmpty()) {
431 if (!quiet && !node->isReimp()) { // ### might be unnecessary
432 node->location().warning(tr("No documentation for '%1'")
433 .arg(marker->plainFullName(node)));
434 }
435 }
436 else {
437 if (node->type() == Node::Function) {
438 const FunctionNode *func = static_cast<const FunctionNode *>(node);
439 if (func->reimplementedFrom() != 0)
440 generateReimplementedFrom(func, marker);
441 }
442
443 if (!generateText(node->doc().body(), node, marker)) {
444 if (node->isReimp())
445 return;
446 }
447
448 if (node->type() == Node::Enum) {
449 const EnumNode *enume = (const EnumNode *) node;
450
451 QSet<QString> definedItems;
452 QList<EnumItem>::ConstIterator it = enume->items().begin();
453 while (it != enume->items().end()) {
454 definedItems.insert((*it).name());
455 ++it;
456 }
457
458 QSet<QString> documentedItems = enume->doc().enumItemNames().toSet();
459 QSet<QString> allItems = definedItems + documentedItems;
460 if (allItems.count() > definedItems.count() ||
461 allItems.count() > documentedItems.count()) {
462 QSet<QString>::ConstIterator a = allItems.begin();
463 while (a != allItems.end()) {
464 if (!definedItems.contains(*a)) {
465 QString details;
466 QString best = nearestName(*a, definedItems);
467 if (!best.isEmpty() && !documentedItems.contains(best))
468 details = tr("Maybe you meant '%1'?").arg(best);
469
470 node->doc().location().warning(
471 tr("No such enum item '%1' in %2").arg(*a).arg(marker->plainFullName(node)),
472 details);
473 }
474 else if (!documentedItems.contains(*a)) {
475 node->doc().location().warning(
476 tr("Undocumented enum item '%1' in %2").arg(*a).arg(marker->plainFullName(node)));
477 }
478 ++a;
479 }
480 }
481 }
482 else if (node->type() == Node::Function) {
483 const FunctionNode *func = static_cast<const FunctionNode *>(node);
484 QSet<QString> definedParams;
485 QList<Parameter>::ConstIterator p = func->parameters().begin();
486 while (p != func->parameters().end()) {
487 if ((*p).name().isEmpty() && (*p).leftType() != QLatin1String("...")
488 && func->name() != QLatin1String("operator++")
489 && func->name() != QLatin1String("operator--")) {
490 node->doc().location().warning(tr("Missing parameter name"));
491 }
492 else {
493 definedParams.insert((*p).name());
494 }
495 ++p;
496 }
497
498 QSet<QString> documentedParams = func->doc().parameterNames();
499 QSet<QString> allParams = definedParams + documentedParams;
500 if (allParams.count() > definedParams.count()
501 || allParams.count() > documentedParams.count()) {
502 QSet<QString>::ConstIterator a = allParams.begin();
503 while (a != allParams.end()) {
504 if (!definedParams.contains(*a)) {
505 QString details;
506 QString best = nearestName(*a, definedParams);
507 if (!best.isEmpty())
508 details = tr("Maybe you meant '%1'?").arg(best);
509
510 node->doc().location().warning(
511 tr("No such parameter '%1' in %2").arg(*a).arg(marker->plainFullName(node)),
512 details);
513 }
514 else if (!(*a).isEmpty() && !documentedParams.contains(*a)) {
515 bool needWarning = (func->status() > Node::Obsolete);
516 if (func->overloadNumber() > 1) {
517 FunctionNode *primaryFunc =
518 func->parent()->findFunctionNode(func->name());
519 if (primaryFunc) {
520 foreach (const Parameter &param,
521 primaryFunc->parameters()) {
522 if (param.name() == *a) {
523 needWarning = false;
524 break;
525 }
526 }
527 }
528 }
529 if (needWarning && !func->isReimp())
530 node->doc().location().warning(
531 tr("Undocumented parameter '%1' in %2")
532 .arg(*a).arg(marker->plainFullName(node)));
533 }
534 ++a;
535 }
536 }
537 /*
538 Something like this return value check should
539 be implemented at some point.
540 */
541 if (func->status() > Node::Obsolete && func->returnType() == "bool"
542 && func->reimplementedFrom() == 0 && !func->isOverload()) {
543 QString body = func->doc().body().toString();
544 if (!body.contains("return", Qt::CaseInsensitive))
545 node->doc().location().warning(tr("Undocumented return value"));
546 }
547 }
548 }
549
550 if (node->type() == Node::Fake) {
551 const FakeNode *fake = static_cast<const FakeNode *>(node);
552 if (fake->subType() == Node::File) {
553 Text text;
554 Quoter quoter;
555 Doc::quoteFromFile(fake->doc().location(), quoter, fake->name());
556 QString code = quoter.quoteTo(fake->location(), "", "");
557 CodeMarker *codeMarker = CodeMarker::markerForFileName(fake->name());
558 text << Atom(codeMarker->atomType(), code);
559 generateText(text, fake, codeMarker);
560 }
561 }
562}
563
564void Generator::generateAlsoList(const Node *node, CodeMarker *marker)
565{
566 QList<Text> alsoList = node->doc().alsoList();
567 supplementAlsoList(node, alsoList);
568
569 if (!alsoList.isEmpty()) {
570 Text text;
571 text << Atom::ParaLeft
572 << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
573 << "See also "
574 << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD);
575
576 for (int i = 0; i < alsoList.size(); ++i)
577 text << alsoList.at(i) << separator(i, alsoList.size());
578
579 text << Atom::ParaRight;
580 generateText(text, node, marker);
581 }
582}
583
584/*!
585 Generate a list of maintainers in the output
586 */
587void Generator::generateMaintainerList(const InnerNode* node, CodeMarker* marker)
588{
589 QStringList sl = getMetadataElements(node,"maintainer");
590
591 if (!sl.isEmpty()) {
592 Text text;
593 text << Atom::ParaLeft
594 << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
595 << "Maintained by: "
596 << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD);
597
598 for (int i = 0; i < sl.size(); ++i)
599 text << sl.at(i) << separator(i, sl.size());
600
601 text << Atom::ParaRight;
602 generateText(text, node, marker);
603 }
604}
605
606void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker)
607{
608 QList<RelatedClass>::ConstIterator r;
609 int index;
610
611 if (!classe->baseClasses().isEmpty()) {
612 Text text;
613 text << Atom::ParaLeft
614 << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
615 << "Inherits: "
616 << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD);
617
618 r = classe->baseClasses().begin();
619 index = 0;
620 while (r != classe->baseClasses().end()) {
621 text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node))
622 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
623 << Atom(Atom::String, (*r).dataTypeWithTemplateArgs)
624 << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
625
626 if ((*r).access == Node::Protected) {
627 text << " (protected)";
628 }
629 else if ((*r).access == Node::Private) {
630 text << " (private)";
631 }
632 text << separator(index++, classe->baseClasses().count());
633 ++r;
634 }
635 text << Atom::ParaRight;
636 generateText(text, classe, marker);
637 }
638}
639
640#ifdef QDOC_QML
641/*!
642 */
643void Generator::generateQmlInherits(const QmlClassNode* , CodeMarker* )
644{
645 // stub.
646}
647#endif
648
649void Generator::generateInheritedBy(const ClassNode *classe,
650 CodeMarker *marker)
651{
652 if (!classe->derivedClasses().isEmpty()) {
653 Text text;
654 text << Atom::ParaLeft
655 << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
656 << "Inherited by: "
657 << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD);
658
659 appendSortedNames(text, classe, classe->derivedClasses(), marker);
660 text << Atom::ParaRight;
661 generateText(text, classe, marker);
662 }
663}
664
665/*!
666 This function is called when the documentation for an
667 example is being formatted. It outputs the list of source
668 files comprising the example, and the list of images used
669 by the example. The images are copied into a subtree of
670 \c{...doc/html/images/used-in-examples/...}
671 */
672void Generator::generateFileList(const FakeNode* fake,
673 CodeMarker* marker,
674 Node::SubType subtype,
675 const QString& tag)
676{
677 int count = 0;
678 Text text;
679 OpenedList openedList(OpenedList::Bullet);
680
681 text << Atom::ParaLeft << tag << Atom::ParaRight
682 << Atom(Atom::ListLeft, openedList.styleString());
683
684 foreach (const Node* child, fake->childNodes()) {
685 if (child->subType() == subtype) {
686 ++count;
687 QString file = child->name();
688 if (subtype == Node::Image) {
689 if (!file.isEmpty()) {
690 QDir dirInfo;
691 QString userFriendlyFilePath;
692 QString srcPath = Config::findFile(fake->location(),
693 QStringList(),
694 exampleDirs,
695 file,
696 exampleImgExts,
697 userFriendlyFilePath);
698 userFriendlyFilePath.truncate(userFriendlyFilePath.lastIndexOf('/'));
699
700 QString imgOutDir = outDir + "/images/used-in-examples/" + userFriendlyFilePath;
701 if (!dirInfo.mkpath(imgOutDir))
702 fake->location().fatal(tr("Cannot create output directory '%1'")
703 .arg(imgOutDir));
704
705 QString imgOutName = Config::copyFile(fake->location(),
706 srcPath,
707 file,
708 imgOutDir);
709 }
710
711 }
712
713 openedList.next();
714 text << Atom(Atom::ListItemNumber, openedList.numberString())
715 << Atom(Atom::ListItemLeft, openedList.styleString())
716 << Atom::ParaLeft
717 << Atom(Atom::Link, file)
718 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
719 << file
720 << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
721 << Atom::ParaRight
722 << Atom(Atom::ListItemRight, openedList.styleString());
723 }
724 }
725 text << Atom(Atom::ListRight, openedList.styleString());
726 if (count > 0)
727 generateText(text, fake, marker);
728}
729
730void Generator::generateExampleFiles(const FakeNode *fake, CodeMarker *marker)
731{
732 if (fake->childNodes().isEmpty())
733 return;
734 generateFileList(fake, marker, Node::File, QString("Files:"));
735 generateFileList(fake, marker, Node::Image, QString("Images:"));
736}
737
738QString Generator::indent(int level, const QString& markedCode)
739{
740 if (level == 0)
741 return markedCode;
742
743 QString t;
744 int column = 0;
745
746 int i = 0;
747 while (i < (int) markedCode.length()) {
748 if (markedCode.at(i) == QLatin1Char('\n')) {
749 column = 0;
750 }
751 else {
752 if (column == 0) {
753 for (int j = 0; j < level; j++)
754 t += QLatin1Char(' ');
755 }
756 column++;
757 }
758 t += markedCode.at(i++);
759 }
760 return t;
761}
762
763QString Generator::plainCode(const QString& markedCode)
764{
765 QString t = markedCode;
766 t.replace(tag, QString());
767 t.replace(quot, QLatin1String("\""));
768 t.replace(gt, QLatin1String(">"));
769 t.replace(lt, QLatin1String("<"));
770 t.replace(amp, QLatin1String("&"));
771 return t;
772}
773
774QString Generator::typeString(const Node *node)
775{
776 switch (node->type()) {
777 case Node::Namespace:
778 return "namespace";
779 case Node::Class:
780 return "class";
781 case Node::Fake:
782 {
783 switch (node->subType()) {
784 case Node::QmlClass:
785 return "element";
786 case Node::QmlPropertyGroup:
787 return "property group";
788 case Node::QmlBasicType:
789 return "type";
790 default:
791 return "documentation";
792 }
793 }
794 case Node::Enum:
795 return "enum";
796 case Node::Typedef:
797 return "typedef";
798 case Node::Function:
799 return "function";
800 case Node::Property:
801 return "property";
802 default:
803 return "documentation";
804 }
805}
806
807QString Generator::imageFileName(const Node *relative, const QString& fileBase)
808{
809 QString userFriendlyFilePath;
810 QString filePath = Config::findFile(
811 relative->doc().location(), imageFiles, imageDirs, fileBase,
812 imgFileExts[format()], userFriendlyFilePath);
813
814 if (filePath.isEmpty())
815 return QString();
816
817 QString path = Config::copyFile(relative->doc().location(),
818 filePath,
819 userFriendlyFilePath,
820 outputDir() + QLatin1String("/images"));
821 if (path[0] != '/')
822 return QLatin1String("images/") + path;
823 return QLatin1String("images") + path;
824}
825
826void Generator::setImageFileExtensions(const QStringList& extensions)
827{
828 imgFileExts[format()] = extensions;
829}
830
831void Generator::unknownAtom(const Atom *atom)
832{
833 Location::internalError(tr("unknown atom type '%1' in %2 generator")
834 .arg(atom->typeString()).arg(format()));
835}
836
837bool Generator::matchAhead(const Atom *atom, Atom::Type expectedAtomType)
838{
839 return atom->next() != 0 && atom->next()->type() == expectedAtomType;
840}
841
842void Generator::supplementAlsoList(const Node *node, QList<Text> &alsoList)
843{
844 if (node->type() == Node::Function) {
845 const FunctionNode *func = static_cast<const FunctionNode *>(node);
846 if (func->overloadNumber() == 1) {
847 QString alternateName;
848 const FunctionNode *alternateFunc = 0;
849
850 if (func->name().startsWith("set") && func->name().size() >= 4) {
851 alternateName = func->name()[3].toLower();
852 alternateName += func->name().mid(4);
853 alternateFunc = func->parent()->findFunctionNode(alternateName);
854
855 if (!alternateFunc) {
856 alternateName = "is" + func->name().mid(3);
857 alternateFunc = func->parent()->findFunctionNode(alternateName);
858 if (!alternateFunc) {
859 alternateName = "has" + func->name().mid(3);
860 alternateFunc = func->parent()->findFunctionNode(alternateName);
861 }
862 }
863 }
864 else if (!func->name().isEmpty()) {
865 alternateName = "set";
866 alternateName += func->name()[0].toUpper();
867 alternateName += func->name().mid(1);
868 alternateFunc = func->parent()->findFunctionNode(alternateName);
869 }
870
871 if (alternateFunc && alternateFunc->access() != Node::Private) {
872 int i;
873 for (i = 0; i < alsoList.size(); ++i) {
874 if (alsoList.at(i).toString().contains(alternateName))
875 break;
876 }
877
878 if (i == alsoList.size()) {
879 alternateName += "()";
880
881 Text also;
882 also << Atom(Atom::Link, alternateName)
883 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
884 << alternateName
885 << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
886 alsoList.prepend(also);
887 }
888 }
889 }
890 }
891}
892
893QMap<QString, QString>& Generator::formattingLeftMap()
894{
895 return fmtLeftMaps[format()];
896}
897
898QMap<QString, QString>& Generator::formattingRightMap()
899{
900 return fmtRightMaps[format()];
901}
902
903/*
904 Trims trailimng whitespace off the \a string and returns
905 the trimmed string.
906 */
907QString Generator::trimmedTrailing(const QString& string)
908{
909 QString trimmed = string;
910 while (trimmed.length() > 0 && trimmed[trimmed.length() - 1].isSpace())
911 trimmed.truncate(trimmed.length() - 1);
912 return trimmed;
913}
914
915void Generator::generateStatus(const Node *node, CodeMarker *marker)
916{
917 Text text;
918
919 switch (node->status()) {
920 case Node::Commendable:
921 case Node::Main:
922 break;
923 case Node::Preliminary:
924 text << Atom::ParaLeft
925 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
926 << "This "
927 << typeString(node)
928 << " is under development and is subject to change."
929 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
930 << Atom::ParaRight;
931 break;
932 case Node::Deprecated:
933 text << Atom::ParaLeft;
934 if (node->isInnerNode())
935 text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD);
936 text << "This " << typeString(node) << " is deprecated.";
937 if (node->isInnerNode())
938 text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD);
939 text << Atom::ParaRight;
940 break;
941 case Node::Obsolete:
942 text << Atom::ParaLeft;
943 if (node->isInnerNode())
944 text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD);
945 text << "This " << typeString(node) << " is obsolete.";
946 if (node->isInnerNode())
947 text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD);
948 text << " It is provided to keep old source code working. "
949 << "We strongly advise against "
950 << "using it in new code." << Atom::ParaRight;
951 break;
952 case Node::Compat:
953 // reimplemented in HtmlGenerator subclass
954 if (node->isInnerNode()) {
955 text << Atom::ParaLeft
956 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
957 << "This "
958 << typeString(node)
959 << " is part of the Qt 3 compatibility layer."
960 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
961 << " It is provided to keep old source code working. "
962 << "We strongly advise against "
963 << "using it in new code. See "
964 << Atom(Atom::AutoLink, "Porting to Qt 4")
965 << " for more information."
966 << Atom::ParaRight;
967 }
968 break;
969 case Node::Internal:
970 default:
971 break;
972 }
973 generateText(text, node, marker);
974}
975
976void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker)
977{
978 Text text;
979 Text theStockLink;
980 Node::ThreadSafeness threadSafeness = node->threadSafeness();
981
982 Text rlink;
983 rlink << Atom(Atom::Link,"reentrant")
984 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
985 << "reentrant"
986 << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
987
988 Text tlink;
989 tlink << Atom(Atom::Link,"thread-safe")
990 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
991 << "thread-safe"
992 << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
993
994 switch (threadSafeness) {
995 case Node::UnspecifiedSafeness:
996 break;
997 case Node::NonReentrant:
998 text << Atom::ParaLeft
999 << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
1000 << "Warning:"
1001 << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD)
1002 << " This "
1003 << typeString(node)
1004 << " is not "
1005 << rlink
1006 << "."
1007 << Atom::ParaRight;
1008 break;
1009 case Node::Reentrant:
1010 case Node::ThreadSafe:
1011 text << Atom::ParaLeft
1012 << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
1013 << "Note:"
1014 << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD)
1015 << " ";
1016
1017 if (node->isInnerNode()) {
1018 const InnerNode* innerNode = static_cast<const InnerNode*>(node);
1019 text << "All functions in this "
1020 << typeString(node)
1021 << " are ";
1022 if (threadSafeness == Node::ThreadSafe)
1023 text << tlink;
1024 else
1025 text << rlink;
1026
1027 bool exceptions = false;
1028 NodeList reentrant;
1029 NodeList threadsafe;
1030 NodeList nonreentrant;
1031 NodeList::ConstIterator c = innerNode->childNodes().begin();
1032 while (c != innerNode->childNodes().end()) {
1033
1034 if ((*c)->status() != Node::Obsolete){
1035 switch ((*c)->threadSafeness()) {
1036 case Node::Reentrant:
1037 reentrant.append(*c);
1038 if (threadSafeness == Node::ThreadSafe)
1039 exceptions = true;
1040 break;
1041 case Node::ThreadSafe:
1042 threadsafe.append(*c);
1043 if (threadSafeness == Node::Reentrant)
1044 exceptions = true;
1045 break;
1046 case Node::NonReentrant:
1047 nonreentrant.append(*c);
1048 exceptions = true;
1049 break;
1050 default:
1051 break;
1052 }
1053 }
1054 ++c;
1055 }
1056 if (!exceptions)
1057 text << ".";
1058 else if (threadSafeness == Node::Reentrant) {
1059 if (nonreentrant.isEmpty()) {
1060 if (!threadsafe.isEmpty()) {
1061 text << ", but ";
1062 appendFullNames(text,threadsafe,innerNode,marker);
1063 singularPlural(text,threadsafe);
1064 text << " also " << tlink << ".";
1065 }
1066 else
1067 text << ".";
1068 }
1069 else {
1070 text << ", except for ";
1071 appendFullNames(text,nonreentrant,innerNode,marker);
1072 text << ", which";
1073 singularPlural(text,nonreentrant);
1074 text << " nonreentrant.";
1075 if (!threadsafe.isEmpty()) {
1076 text << " ";
1077 appendFullNames(text,threadsafe,innerNode,marker);
1078 singularPlural(text,threadsafe);
1079 text << " " << tlink << ".";
1080 }
1081 }
1082 }
1083 else { // thread-safe
1084 if (!nonreentrant.isEmpty() || !reentrant.isEmpty()) {
1085 text << ", except for ";
1086 if (!reentrant.isEmpty()) {
1087 appendFullNames(text,reentrant,innerNode,marker);
1088 text << ", which";
1089 singularPlural(text,reentrant);
1090 text << " only " << rlink;
1091 if (!nonreentrant.isEmpty())
1092 text << ", and ";
1093 }
1094 if (!nonreentrant.isEmpty()) {
1095 appendFullNames(text,nonreentrant,innerNode,marker);
1096 text << ", which";
1097 singularPlural(text,nonreentrant);
1098 text << " nonreentrant.";
1099 }
1100 text << ".";
1101 }
1102 }
1103 }
1104 else {
1105 text << "This " << typeString(node) << " is ";
1106 if (threadSafeness == Node::ThreadSafe)
1107 text << tlink;
1108 else
1109 text << rlink;
1110 text << ".";
1111 }
1112 text << Atom::ParaRight;
1113 }
1114 generateText(text,node,marker);
1115}
1116
1117void Generator::generateSince(const Node *node, CodeMarker *marker)
1118{
1119 if (!node->since().isEmpty()) {
1120 Text text;
1121 text << Atom::ParaLeft
1122 << "This "
1123 << typeString(node);
1124 if (node->type() == Node::Enum)
1125 text << " was introduced or modified in ";
1126 else
1127 text << " was introduced in ";
1128
1129 QStringList since = node->since().split(" ");
1130 if (since.count() == 1) {
1131 // Handle legacy use of \since <version>.
1132 if (project.isEmpty())
1133 text << "version";
1134 else
1135 text << project;
1136 text << " " << since[0];
1137 } else {
1138 // Reconstruct the <project> <version> string.
1139 text << " " << since.join(" ");
1140 }
1141
1142 text << "." << Atom::ParaRight;
1143 generateText(text, node, marker);
1144 }
1145}
1146
1147void Generator::generateReimplementedFrom(const FunctionNode *func,
1148 CodeMarker *marker)
1149{
1150 if (func->reimplementedFrom() != 0) {
1151 const FunctionNode *from = func->reimplementedFrom();
1152 if (from->access() != Node::Private &&
1153 from->parent()->access() != Node::Private) {
1154 Text text;
1155 text << Atom::ParaLeft << "Reimplemented from ";
1156 QString fullName = from->parent()->name() + "::" + from->name() + "()";
1157 appendFullName(text, from->parent(), fullName, from);
1158 text << "." << Atom::ParaRight;
1159 generateText(text, func, marker);
1160 }
1161 }
1162}
1163
1164const Atom *Generator::generateAtomList(const Atom *atom,
1165 const Node *relative,
1166 CodeMarker *marker,
1167 bool generate,
1168 int &numAtoms)
1169{
1170 while (atom) {
1171 if (atom->type() == Atom::FormatIf) {
1172 int numAtoms0 = numAtoms;
1173 bool rightFormat = canHandleFormat(atom->string());
1174 atom = generateAtomList(atom->next(),
1175 relative,
1176 marker,
1177 generate && rightFormat,
1178 numAtoms);
1179 if (!atom)
1180 return 0;
1181
1182 if (atom->type() == Atom::FormatElse) {
1183 ++numAtoms;
1184 atom = generateAtomList(atom->next(),
1185 relative,
1186 marker,
1187 generate && !rightFormat,
1188 numAtoms);
1189 if (!atom)
1190 return 0;
1191 }
1192
1193 if (atom->type() == Atom::FormatEndif) {
1194 if (generate && numAtoms0 == numAtoms) {
1195 relative->location().warning(tr("Output format %1 not handled %2")
1196 .arg(format()).arg(outFileName()));
1197 Atom unhandledFormatAtom(Atom::UnhandledFormat, format());
1198 generateAtomList(&unhandledFormatAtom,
1199 relative,
1200 marker,
1201 generate,
1202 numAtoms);
1203 }
1204 atom = atom->next();
1205 }
1206 }
1207 else if (atom->type() == Atom::FormatElse ||
1208 atom->type() == Atom::FormatEndif) {
1209 return atom;
1210 }
1211 else {
1212 int n = 1;
1213 if (generate) {
1214 n += generateAtom(atom, relative, marker);
1215 numAtoms += n;
1216 }
1217 while (n-- > 0)
1218 atom = atom->next();
1219 }
1220 }
1221 return 0;
1222}
1223
1224void Generator::appendFullName(Text& text,
1225 const Node *apparentNode,
1226 const Node *relative,
1227 CodeMarker *marker,
1228 const Node *actualNode)
1229{
1230 if (actualNode == 0)
1231 actualNode = apparentNode;
1232 text << Atom(Atom::LinkNode, CodeMarker::stringForNode(actualNode))
1233 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
1234 << Atom(Atom::String, marker->plainFullName(apparentNode, relative))
1235 << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
1236}
1237
1238void Generator::appendFullName(Text& text,
1239 const Node *apparentNode,
1240 const QString& fullName,
1241 const Node *actualNode)
1242{
1243 if (actualNode == 0)
1244 actualNode = apparentNode;
1245 text << Atom(Atom::LinkNode, CodeMarker::stringForNode(actualNode))
1246 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
1247 << Atom(Atom::String, fullName)
1248 << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
1249}
1250
1251void Generator::appendFullNames(Text& text,
1252 const NodeList& nodes,
1253 const Node* relative,
1254 CodeMarker* marker)
1255{
1256 NodeList::ConstIterator n = nodes.begin();
1257 int index = 0;
1258 while (n != nodes.end()) {
1259 appendFullName(text,*n,relative,marker);
1260 text << comma(index++,nodes.count());
1261 ++n;
1262 }
1263}
1264
1265void Generator::appendSortedNames(Text& text,
1266 const ClassNode *classe,
1267 const QList<RelatedClass> &classes,
1268 CodeMarker *marker)
1269{
1270 QList<RelatedClass>::ConstIterator r;
1271 QMap<QString,Text> classMap;
1272 int index = 0;
1273
1274 r = classes.begin();
1275 while (r != classes.end()) {
1276 if ((*r).node->access() == Node::Public &&
1277 (*r).node->status() != Node::Internal
1278 && !(*r).node->doc().isEmpty()) {
1279 Text className;
1280 appendFullName(className, (*r).node, classe, marker);
1281 classMap[className.toString().toLower()] = className;
1282 }
1283 ++r;
1284 }
1285
1286 QStringList classNames = classMap.keys();
1287 classNames.sort();
1288
1289 foreach (const QString &className, classNames) {
1290 text << classMap[className];
1291 text << separator(index++, classNames.count());
1292 }
1293}
1294
1295void Generator::appendSortedQmlNames(Text& text,
1296 const Node* base,
1297 const NodeList& subs,
1298 CodeMarker *marker)
1299{
1300 QMap<QString,Text> classMap;
1301 int index = 0;
1302
1303#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
1304 qDebug() << "Generator::appendSortedQmlNames():" << base->name() << "is inherited by...";
1305#endif
1306 for (int i = 0; i < subs.size(); ++i) {
1307 Text t;
1308#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
1309 qDebug() << " " << subs[i]->name();
1310#endif
1311 appendFullName(t, subs[i], base, marker);
1312 classMap[t.toString().toLower()] = t;
1313 }
1314
1315 QStringList names = classMap.keys();
1316 names.sort();
1317
1318 foreach (const QString &name, names) {
1319 text << classMap[name];
1320 text << separator(index++, names.count());
1321 }
1322}
1323
1324int Generator::skipAtoms(const Atom *atom, Atom::Type type) const
1325{
1326 int skipAhead = 0;
1327 atom = atom->next();
1328 while (atom != 0 && atom->type() != type) {
1329 skipAhead++;
1330 atom = atom->next();
1331 }
1332 return skipAhead;
1333}
1334
1335QString Generator::fullName(const Node *node,
1336 const Node *relative,
1337 CodeMarker *marker) const
1338{
1339 if (node->type() == Node::Fake)
1340 return static_cast<const FakeNode *>(node)->title();
1341 else if (node->type() == Node::Class &&
1342 !(static_cast<const ClassNode *>(node))->serviceName().isEmpty())
1343 return (static_cast<const ClassNode *>(node))->serviceName();
1344 else
1345 return marker->plainFullName(node, relative);
1346}
1347
1348QString Generator::outputPrefix(const QString &nodeType)
1349{
1350 return outputPrefixes[nodeType];
1351}
1352
1353/*!
1354 Looks up the tag \a t in the map of metadata values for the
1355 current topic in \a inner. If a value for the tag is found,
1356 the value is returned.
1357
1358 \note If \a t is found in the metadata map, it is erased.
1359 i.e. Once you call this function for a particular \a t,
1360 you consume \a t.
1361 */
1362QString Generator::getMetadataElement(const InnerNode* inner, const QString& t)
1363{
1364 QString s;
1365 QStringMultiMap& metaTagMap = const_cast<QStringMultiMap&>(inner->doc().metaTagMap());
1366 QStringMultiMap::iterator i = metaTagMap.find(t);
1367 if (i != metaTagMap.end()) {
1368 s = i.value();
1369 metaTagMap.erase(i);
1370 }
1371 return s;
1372}
1373
1374/*!
1375 Looks up the tag \a t in the map of metadata values for the
1376 current topic in \a inner. If values for the tag are found,
1377 they are returned in a string list.
1378
1379 \note If \a t is found in the metadata map, all the pairs
1380 having the key \a t are erased. i.e. Once you call this
1381 function for a particular \a t, you consume \a t.
1382 */
1383QStringList Generator::getMetadataElements(const InnerNode* inner, const QString& t)
1384{
1385 QStringList s;
1386 QStringMultiMap& metaTagMap = const_cast<QStringMultiMap&>(inner->doc().metaTagMap());
1387 s = metaTagMap.values(t);
1388 if (!s.isEmpty())
1389 metaTagMap.remove(t);
1390 return s;
1391}
1392
1393/*!
1394 For generating the "New Classes... in 4.6" section on the
1395 What's New in 4.6" page.
1396 */
1397void Generator::findAllSince(const InnerNode *node)
1398{
1399 NodeList::const_iterator child = node->childNodes().constBegin();
1400
1401 // Traverse the tree, starting at the node supplied.
1402
1403 while (child != node->childNodes().constEnd()) {
1404
1405 QString sinceString = (*child)->since();
1406
1407 if (((*child)->access() != Node::Private) && !sinceString.isEmpty()) {
1408
1409 // Insert a new entry into each map for each new since string found.
1410 NewSinceMaps::iterator nsmap = newSinceMaps.find(sinceString);
1411 if (nsmap == newSinceMaps.end())
1412 nsmap = newSinceMaps.insert(sinceString,NodeMultiMap());
1413
1414 NewClassMaps::iterator ncmap = newClassMaps.find(sinceString);
1415 if (ncmap == newClassMaps.end())
1416 ncmap = newClassMaps.insert(sinceString,NodeMap());
1417
1418 NewClassMaps::iterator nqcmap = newQmlClassMaps.find(sinceString);
1419 if (nqcmap == newQmlClassMaps.end())
1420 nqcmap = newQmlClassMaps.insert(sinceString,NodeMap());
1421
1422 if ((*child)->type() == Node::Function) {
1423 // Insert functions into the general since map.
1424 FunctionNode *func = static_cast<FunctionNode *>(*child);
1425 if ((func->status() > Node::Obsolete) &&
1426 (func->metaness() != FunctionNode::Ctor) &&
1427 (func->metaness() != FunctionNode::Dtor)) {
1428 nsmap.value().insert(func->name(),(*child));
1429 }
1430 }
1431 else if ((*child)->url().isEmpty()) {
1432 if ((*child)->type() == Node::Class && !(*child)->doc().isEmpty()) {
1433 // Insert classes into the since and class maps.
1434 QString className = (*child)->name();
1435 if ((*child)->parent() &&
1436 (*child)->parent()->type() == Node::Namespace &&
1437 !(*child)->parent()->name().isEmpty())
1438 className = (*child)->parent()->name()+"::"+className;
1439
1440 nsmap.value().insert(className,(*child));
1441 ncmap.value().insert(className,(*child));
1442 }
1443 else if ((*child)->subType() == Node::QmlClass) {
1444 // Insert QML elements into the since and element maps.
1445 QString className = (*child)->name();
1446 if ((*child)->parent() &&
1447 (*child)->parent()->type() == Node::Namespace &&
1448 !(*child)->parent()->name().isEmpty())
1449 className = (*child)->parent()->name()+"::"+className;
1450
1451 nsmap.value().insert(className,(*child));
1452 nqcmap.value().insert(className,(*child));
1453 }
1454 else if ((*child)->type() == Node::QmlProperty) {
1455 // Insert QML properties into the since map.
1456 QString propertyName = (*child)->name();
1457 nsmap.value().insert(propertyName,(*child));
1458 }
1459 }
1460 else {
1461 // Insert external documents into the general since map.
1462 QString name = (*child)->name();
1463 if ((*child)->parent() &&
1464 (*child)->parent()->type() == Node::Namespace &&
1465 !(*child)->parent()->name().isEmpty())
1466 name = (*child)->parent()->name()+"::"+name;
1467
1468 nsmap.value().insert(name,(*child));
1469 }
1470
1471 // Find child nodes with since commands.
1472 if ((*child)->isInnerNode()) {
1473 findAllSince(static_cast<InnerNode *>(*child));
1474 }
1475 }
1476 ++child;
1477 }
1478}
1479
1480QT_END_NAMESPACE
1481

Warning: That file was not part of the compilation database. It may have many parsing errors.