~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to tools/qdoc3/generator.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/****************************************************************************
2
2
**
3
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 
4
** All rights reserved.
4
5
** Contact: Nokia Corporation (qt-info@nokia.com)
5
6
**
6
7
** This file is part of the tools applications of the Qt Toolkit.
7
8
**
8
9
** $QT_BEGIN_LICENSE:LGPL$
9
 
** Commercial Usage
10
 
** Licensees holding valid Qt Commercial licenses may use this file in
11
 
** accordance with the Qt Commercial License Agreement provided with the
12
 
** Software or, alternatively, in accordance with the terms contained in
13
 
** a written agreement between you and Nokia.
 
10
** No Commercial Usage
 
11
** This file contains pre-release code and may not be distributed.
 
12
** You may use this file in accordance with the terms and conditions
 
13
** contained in the Technology Preview License Agreement accompanying
 
14
** this package.
14
15
**
15
16
** GNU Lesser General Public License Usage
16
17
** Alternatively, this file may be used under the terms of the GNU Lesser
20
21
** ensure the GNU Lesser General Public License version 2.1 requirements
21
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22
23
**
23
 
** In addition, as a special exception, Nokia gives you certain
24
 
** additional rights. These rights are described in the Nokia Qt LGPL
25
 
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26
 
** package.
27
 
**
28
 
** GNU General Public License Usage
29
 
** Alternatively, this file may be used under the terms of the GNU
30
 
** General Public License version 3.0 as published by the Free Software
31
 
** Foundation and appearing in the file LICENSE.GPL included in the
32
 
** packaging of this file.  Please review the following information to
33
 
** ensure the GNU General Public License version 3.0 requirements will be
34
 
** met: http://www.gnu.org/copyleft/gpl.html.
35
 
**
36
 
** If you are unsure which license is appropriate for your use, please
37
 
** contact the sales department at http://www.qtsoftware.com/contact.
 
24
** In addition, as a special exception, Nokia gives you certain additional
 
25
** rights.  These rights are described in the Nokia Qt LGPL Exception
 
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
27
**
 
28
** If you have questions regarding the use of this file, please contact
 
29
** Nokia at qt-info@nokia.com.
 
30
**
 
31
**
 
32
**
 
33
**
 
34
**
 
35
**
 
36
**
 
37
**
38
38
** $QT_END_LICENSE$
39
39
**
40
40
****************************************************************************/
42
42
/*
43
43
  generator.cpp
44
44
*/
45
 
 
 
45
#include <QtCore>
46
46
#include <qdir.h>
47
 
 
 
47
#include <qdebug.h>
48
48
#include "codemarker.h"
49
49
#include "config.h"
50
50
#include "doc.h"
68
68
QString Generator::outDir;
69
69
QString Generator::project;
70
70
 
71
 
static Text stockLink(const QString &target)
 
71
static void singularPlural(Text& text, const NodeList& nodes)
72
72
{
73
 
    return Text() << Atom(Atom::Link, target) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
74
 
                  << target << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
 
73
    if (nodes.count() == 1)
 
74
        text << " is";
 
75
    else
 
76
        text << " are";
75
77
}
76
78
 
77
79
Generator::Generator()
78
 
    : amp("&amp;"), lt("&lt;"), gt("&gt;"), quot("&quot;"), tag("</?@[^>]*>")
 
80
    : amp("&amp;"),
 
81
      lt("&lt;"),
 
82
      gt("&gt;"),
 
83
      quot("&quot;"),
 
84
      tag("</?@[^>]*>")
79
85
{
80
86
    generators.prepend(this);
81
87
}
123
129
    QSet<QString> formats = config.subVars(imagesDotFileExtensions);
124
130
    QSet<QString>::ConstIterator f = formats.begin();
125
131
    while (f != formats.end()) {
126
 
        imgFileExts[*f] = config.getStringList(imagesDotFileExtensions + Config::dot + *f);
 
132
        imgFileExts[*f] = config.getStringList(imagesDotFileExtensions +
 
133
                                               Config::dot + *f);
127
134
        ++f;
128
135
    }
129
136
 
131
138
    while (g != generators.end()) {
132
139
        if (outputFormats.contains((*g)->format())) {
133
140
            (*g)->initializeGenerator(config);
134
 
            QStringList extraImages = config.getStringList(CONFIG_EXTRAIMAGES + Config::dot
135
 
                                                           + (*g)->format());
 
141
            QStringList extraImages = config.getStringList(CONFIG_EXTRAIMAGES +
 
142
                                                           Config::dot +
 
143
                                                           (*g)->format());
136
144
            QStringList::ConstIterator e = extraImages.begin();
137
145
            while (e != extraImages.end()) {
138
146
                QString userFriendlyFilePath;
139
 
                QString filePath = Config::findFile(config.lastLocation(), imageFiles, imageDirs, *e,
140
 
                                                    imgFileExts[(*g)->format()], userFriendlyFilePath);
 
147
                QString filePath = Config::findFile(config.lastLocation(),
 
148
                                                    imageFiles, imageDirs, *e,
 
149
                                                    imgFileExts[(*g)->format()],
 
150
                                                    userFriendlyFilePath);
141
151
                if (!filePath.isEmpty())
142
 
                    Config::copyFile(config.lastLocation(), filePath, userFriendlyFilePath,
143
 
                                         (*g)->outputDir() + "/images");
 
152
                    Config::copyFile(config.lastLocation(),
 
153
                                     filePath,
 
154
                                     userFriendlyFilePath,
 
155
                                     (*g)->outputDir() +
 
156
                                     "/images");
144
157
                ++e;
145
158
            }
146
159
        }
156
169
        QSet<QString> formats = config.subVars(formattingDotName);
157
170
        QSet<QString>::ConstIterator f = formats.begin();
158
171
        while (f != formats.end()) {
159
 
            QString def = config.getString(formattingDotName + Config::dot +
160
 
                                            *f);
 
172
            QString def = config.getString(formattingDotName +
 
173
                                           Config::dot + *f);
161
174
            if (!def.isEmpty()) {
162
175
                int numParams = Config::numParams(def);
163
176
                int numOccs = def.count("\1");
164
177
 
165
178
                if (numParams != 1) {
166
 
                    config.lastLocation().warning(tr("Formatting '%1' must have exactly one"
167
 
                                                     " parameter (found %2)")
168
 
                                                 .arg(*n).arg(numParams));
 
179
                    config.lastLocation().warning(tr("Formatting '%1' must "
 
180
                                                     "have exactly one "
 
181
                                                     "parameter (found %2)")
 
182
                                                  .arg(*n).arg(numParams));
169
183
                }
170
184
                else if (numOccs > 1) {
171
 
                    config.lastLocation().fatal(tr("Formatting '%1' must contain exactly one"
172
 
                                                    " occurrence of '\\1' (found %2)")
 
185
                    config.lastLocation().fatal(tr("Formatting '%1' must "
 
186
                                                   "contain exactly one "
 
187
                                                   "occurrence of '\\1' "
 
188
                                                   "(found %2)")
173
189
                                                .arg(*n).arg(numOccs));
174
190
                }
175
191
                else {
241
257
{
242
258
}
243
259
 
244
 
void Generator::generateText(const Text& text,
 
260
bool Generator::generateText(const Text& text,
245
261
                             const Node *relative,
246
262
                             CodeMarker *marker)
247
263
{
254
270
                         true,
255
271
                         numAtoms);
256
272
        endText(relative, marker);
 
273
        return true;
257
274
    }
 
275
    return false;
258
276
}
259
277
 
260
278
#ifdef QDOC_QML
261
 
void Generator::generateQmlText(const Text& text,
 
279
/*!
 
280
  Extract sections of markup text surrounded by \e qmltext
 
281
  and \e endqmltext and output them.
 
282
 */
 
283
bool Generator::generateQmlText(const Text& text,
262
284
                                const Node *relative,
263
 
                                CodeMarker *marker)
 
285
                                CodeMarker *marker,
 
286
                                const QString& /* qmlName */ )
264
287
{
265
 
    if (text.firstAtom() != 0) {
266
 
        startText(relative, marker);
267
 
        const Atom *atom = text.firstAtom();
268
 
        while (atom) {
269
 
            if (atom->type() != Atom::QmlText)
270
 
                atom = atom->next();
271
 
            else {
272
 
                atom = atom->next();
273
 
                while (atom && (atom->type() != Atom::EndQmlText)) {
274
 
                    int n = 1 + generateAtom(atom, relative, marker);
275
 
                    while (n-- > 0)
276
 
                        atom = atom->next();
277
 
                }
 
288
    const Atom* atom = text.firstAtom();
 
289
    if (atom == 0)
 
290
        return false;
 
291
 
 
292
    startText(relative, marker);
 
293
    while (atom) {
 
294
        if (atom->type() != Atom::QmlText)
 
295
            atom = atom->next();
 
296
        else {
 
297
            atom = atom->next();
 
298
            while (atom && (atom->type() != Atom::EndQmlText)) {
 
299
                int n = 1 + generateAtom(atom, relative, marker);
 
300
                while (n-- > 0)
 
301
                    atom = atom->next();
278
302
            }
279
303
        }
280
 
        endText(relative, marker);
281
304
    }
 
305
    endText(relative, marker);
 
306
    return true;
282
307
}
283
308
#endif
284
309
 
295
320
    }
296
321
    else if (node->type() == Node::Fake) {
297
322
        const FakeNode *fake = static_cast<const FakeNode *>(node);
298
 
        if (fake->subType() == FakeNode::Example)
 
323
        if (fake->subType() == Node::Example)
299
324
            generateExampleFiles(fake, marker);
300
 
        else if (fake->subType() == FakeNode::File)
 
325
        else if (fake->subType() == Node::File)
301
326
            quiet = true;
302
327
    }
303
328
 
304
329
    if (node->doc().isEmpty()) {
305
 
        if (!quiet) // ### might be unnecessary
 
330
        if (!quiet && !node->isReimp()) // ### might be unnecessary
306
331
            node->location().warning(tr("No documentation for '%1'")
307
332
                            .arg(marker->plainFullName(node)));
308
333
    }
309
334
    else {
310
 
        generateText(node->doc().body(), node, marker);
 
335
        if (node->type() == Node::Function) {
 
336
            const FunctionNode *func = static_cast<const FunctionNode *>(node);
 
337
            if (func->reimplementedFrom() != 0)
 
338
                generateReimplementedFrom(func, marker);
 
339
        }
 
340
        
 
341
        if (!generateText(node->doc().body(), node, marker))
 
342
            if (node->isReimp())
 
343
                return;
311
344
 
312
345
        if (node->type() == Node::Enum) {
313
346
            const EnumNode *enume = (const EnumNode *) node;
345
378
        }
346
379
        else if (node->type() == Node::Function) {
347
380
            const FunctionNode *func = static_cast<const FunctionNode *>(node);
348
 
 
349
381
            QSet<QString> definedParams;
350
382
            QList<Parameter>::ConstIterator p = func->parameters().begin();
351
383
            while (p != func->parameters().end()) {
382
414
                            FunctionNode *primaryFunc =
383
415
                                    func->parent()->findFunctionNode(func->name());
384
416
                            if (primaryFunc) {
385
 
                                foreach (const Parameter &param, primaryFunc->parameters()) {
 
417
                                foreach (const Parameter &param,
 
418
                                         primaryFunc->parameters()) {
386
419
                                    if (param.name() == *a) {
387
420
                                        needWarning = false;
388
421
                                        break;
390
423
                                }
391
424
                            }
392
425
                        }
393
 
                        if (needWarning)
 
426
                        if (needWarning && !func->isReimp())
394
427
                            node->doc().location().warning(
395
 
                                tr("Undocumented parameter '%1' in %2").arg(*a).arg(marker->plainFullName(node)));
 
428
                                tr("Undocumented parameter '%1' in %2")
 
429
                                .arg(*a).arg(marker->plainFullName(node)));
396
430
                    }
397
431
                    ++a;
398
432
                }
404
438
                if (!body.contains("return", Qt::CaseInsensitive))
405
439
                    node->doc().location().warning(tr("Undocumented return value"));
406
440
            }
407
 
 
 
441
#if 0
 
442
            // Now we put this at the top, before the other text.
408
443
            if (func->reimplementedFrom() != 0)
409
444
                generateReimplementedFrom(func, marker);
 
445
#endif            
410
446
        }
411
447
    }
412
448
 
413
449
    if (node->type() == Node::Fake) {
414
450
        const FakeNode *fake = static_cast<const FakeNode *>(node);
415
 
        if (fake->subType() == FakeNode::File) {
 
451
        if (fake->subType() == Node::File) {
416
452
            Text text;
417
453
            Quoter quoter;
418
454
            Doc::quoteFromFile(fake->doc().location(), quoter, fake->name());
459
495
 
460
496
            if ((*r).access == Node::Protected) {
461
497
                text << " (protected)";
462
 
            } else if ((*r).access == Node::Private) {
 
498
            }
 
499
            else if ((*r).access == Node::Private) {
463
500
                text << " (private)";
464
501
            }
465
502
            text << separator(index++, classe->baseClasses().count());
470
507
    }
471
508
}
472
509
 
 
510
#ifdef QDOC_QML
 
511
/*!
 
512
 */
 
513
void Generator::generateQmlInherits(const QmlClassNode* , CodeMarker* )
 
514
{
 
515
    // stub.
 
516
}
 
517
#endif
 
518
 
473
519
void Generator::generateInheritedBy(const ClassNode *classe,
474
520
                                    CodeMarker *marker)
475
521
{
497
543
        QString exampleFile = child->name();
498
544
        openedList.next();
499
545
        text << Atom(Atom::ListItemNumber, openedList.numberString())
500
 
             << Atom(Atom::ListItemLeft, openedList.styleString()) << Atom::ParaLeft
 
546
             << Atom(Atom::ListItemLeft, openedList.styleString())
 
547
             << Atom::ParaLeft
501
548
             << Atom(Atom::Link, exampleFile)
502
549
             << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
503
550
             << exampleFile
504
551
             << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
505
 
             << Atom::ParaRight << Atom(Atom::ListItemRight, openedList.styleString());
 
552
             << Atom::ParaRight
 
553
             << Atom(Atom::ListItemRight, openedList.styleString());
506
554
    }
507
555
    text << Atom(Atom::ListRight, openedList.styleString());
508
556
    generateText(text, fake, marker);
509
557
}
510
558
 
511
 
void Generator::generateModuleWarning(const ClassNode *classe, CodeMarker *marker)
 
559
void Generator::generateModuleWarning(const ClassNode *classe,
 
560
                                      CodeMarker *marker)
512
561
{
513
562
    QString module = classe->moduleName();
514
563
    if (!module.isEmpty()) {
515
564
        Text text;
516
 
        if (Tokenizer::isTrue("defined(consoleedition)")
517
 
                && !editionModuleMap["Console"].contains(module)) {
518
 
            text << Atom::ParaLeft
519
 
                 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
520
 
                 << "This class is not part of the Qt Console Edition."
521
 
                 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
522
 
                 << Atom::ParaRight;
523
 
        }
524
 
        else if (Tokenizer::isTrue("defined(desktoplightedition)")
525
 
                && !editionModuleMap["DesktopLight"].contains(module)) {
526
 
            text << Atom::ParaLeft
527
 
                 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
528
 
                 << "This class is not part of the Qt Desktop Light Edition."
529
 
                 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
530
 
                 << Atom::ParaRight;
531
 
        }
532
 
        else if (module == "Qt3Support" && Tokenizer::isTrue("defined(opensourceedition)")) {
533
 
            text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
534
 
                 << "Note to Qt Desktop Light Edition users:"
 
565
        if (!editionModuleMap["DesktopLight"].contains(module)) {
 
566
            text << Atom::ParaLeft
 
567
                 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
 
568
                 << "This class is not part of the Qt GUI Framework Edition."
 
569
                 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
 
570
                 << Atom::ParaRight;
 
571
        }
 
572
        else if (module == "Qt3Support") {
 
573
            text << Atom::ParaLeft
 
574
                 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
 
575
                 << "Note to Qt GUI Framework Edition users:"
535
576
                 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
536
577
                 << " This class is only available in the "
537
 
                 << Atom(Atom::AutoLink, "Qt Desktop Edition")
 
578
                 << Atom(Atom::AutoLink, "Qt Full Framework Edition")
538
579
                 << "." << Atom::ParaRight;
539
580
        }
540
581
 
558
599
                if (markedCode.at(i - 1) == QLatin1Char('>'))
559
600
                    break;
560
601
            }
561
 
        } else {
 
602
        }
 
603
        else {
562
604
            if (markedCode.at(i) == QLatin1Char('\n')) {
563
605
                column = 0;
564
 
            } else {
 
606
            }
 
607
            else {
565
608
                if (column == 0) {
566
609
                    for (int j = 0; j < level; j++)
567
610
                        t += QLatin1Char(' ');
630
673
void Generator::unknownAtom(const Atom *atom)
631
674
{
632
675
    Location::internalError(tr("unknown atom type '%1' in %2 generator")
633
 
                             .arg(atom->typeString()).arg(format()));
 
676
                            .arg(atom->typeString()).arg(format()));
634
677
}
635
678
 
636
679
bool Generator::matchAhead(const Atom *atom, Atom::Type expectedAtomType)
659
702
                        alternateFunc = func->parent()->findFunctionNode(alternateName);
660
703
                    }
661
704
                }
662
 
            } else if (!func->name().isEmpty()) {
 
705
            }
 
706
            else if (!func->name().isEmpty()) {
663
707
                alternateName = "set";
664
708
                alternateName += func->name()[0].toUpper();
665
709
                alternateName += func->name().mid(1);
715
759
    case Node::Main:
716
760
        break;
717
761
    case Node::Preliminary:
718
 
        text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This "
719
 
             << typeString(node) << " is under development and is subject to change."
720
 
             << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight;
 
762
        text << Atom::ParaLeft
 
763
             << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
 
764
             << "This "
 
765
             << typeString(node)
 
766
             << " is under development and is subject to change."
 
767
             << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
 
768
             << Atom::ParaRight;
721
769
        break;
722
770
    case Node::Deprecated:
723
771
        text << Atom::ParaLeft;
735
783
        text << "This " << typeString(node) << " is obsolete.";
736
784
        if (node->isInnerNode())
737
785
            text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD);
738
 
        text << " It is provided to keep old source code working. We strongly advise against "
 
786
        text << " It is provided to keep old source code working. "
 
787
             << "We strongly advise against "
739
788
             << "using it in new code." << Atom::ParaRight;
740
789
        break;
741
790
    case Node::Compat:
742
791
        // reimplemented in HtmlGenerator subclass
743
792
        if (node->isInnerNode()) {
744
 
            text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This "
745
 
                 << typeString(node) << " is part of the Qt 3 compatibility layer."
 
793
            text << Atom::ParaLeft
 
794
                 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
 
795
                 << "This "
 
796
                 << typeString(node)
 
797
                 << " is part of the Qt 3 compatibility layer."
746
798
                 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
747
 
                 << " It is provided to keep old source code working. We strongly advise against "
 
799
                 << " It is provided to keep old source code working. "
 
800
                 << "We strongly advise against "
748
801
                 << "using it in new code. See "
749
802
                 << Atom(Atom::AutoLink, "Porting to Qt 4")
750
803
                 << " for more information."
762
815
{
763
816
    Text text;
764
817
    Text theStockLink;
765
 
    Node::ThreadSafeness parent = node->parent()->inheritedThreadSafeness();
766
 
 
767
 
    switch (node->threadSafeness()) {
 
818
    Node::ThreadSafeness threadSafeness = node->threadSafeness();
 
819
 
 
820
    Text rlink;
 
821
    rlink << Atom(Atom::Link,"reentrant")
 
822
          << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
 
823
          << "reentrant"
 
824
          << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
 
825
 
 
826
    Text tlink;
 
827
    tlink << Atom(Atom::Link,"thread-safe")
 
828
          << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
 
829
          << "thread-safe"
 
830
          << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
 
831
 
 
832
    switch (threadSafeness) {
768
833
    case Node::UnspecifiedSafeness:
769
834
        break;
770
835
    case Node::NonReentrant:
771
 
        text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "Warning:"
772
 
             << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " This "
773
 
             << typeString(node) << " is not " << stockLink("reentrant") << "." << Atom::ParaRight;
 
836
        text << Atom::ParaLeft
 
837
             << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
 
838
             << "Warning:"
 
839
             << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD)
 
840
             << " This "
 
841
             << typeString(node)
 
842
             << " is not "
 
843
             << rlink
 
844
             << "."
 
845
             << Atom::ParaRight;
774
846
        break;
775
847
    case Node::Reentrant:
776
848
    case Node::ThreadSafe:
777
 
        text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD);
778
 
        if (parent == Node::ThreadSafe) {
779
 
            text << "Warning:";
780
 
        } else {
781
 
            text << "Note:";
782
 
        }
783
 
        text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " ";
784
 
 
785
 
        if (node->threadSafeness() == Node::ThreadSafe)
786
 
            theStockLink = stockLink("thread-safe");
787
 
        else
788
 
            theStockLink = stockLink("reentrant");
 
849
        text << Atom::ParaLeft
 
850
             << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
 
851
             << "Note:"
 
852
             << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD)
 
853
             << " ";
789
854
 
790
855
        if (node->isInnerNode()) {
791
 
            const InnerNode *innerNode = static_cast<const InnerNode *>(node);
792
 
            text << "All the functions in this " << typeString(node) << " are "
793
 
                 << theStockLink;
 
856
            const InnerNode* innerNode = static_cast<const InnerNode*>(node);
 
857
            text << "All functions in this "
 
858
                 << typeString(node)
 
859
                 << " are ";
 
860
            if (threadSafeness == Node::ThreadSafe)
 
861
                text << tlink;
 
862
            else
 
863
                text << rlink;
794
864
 
795
 
            NodeList except;
 
865
            bool exceptions = false;
 
866
            NodeList reentrant;
 
867
            NodeList threadsafe;
 
868
            NodeList nonreentrant;
796
869
            NodeList::ConstIterator c = innerNode->childNodes().begin();
797
870
            while (c != innerNode->childNodes().end()) {
798
 
                if ((*c)->threadSafeness() != Node::UnspecifiedSafeness)
799
 
                    except.append(*c);
 
871
                switch ((*c)->threadSafeness()) {
 
872
                case Node::Reentrant:
 
873
                    reentrant.append(*c);
 
874
                    if (threadSafeness == Node::ThreadSafe)
 
875
                        exceptions = true;
 
876
                    break;
 
877
                case Node::ThreadSafe:
 
878
                    threadsafe.append(*c);
 
879
                    if (threadSafeness == Node::Reentrant)
 
880
                        exceptions = true;
 
881
                    break;
 
882
                case Node::NonReentrant:
 
883
                    nonreentrant.append(*c);
 
884
                    exceptions = true;
 
885
                    break;
 
886
                default:
 
887
                    break;
 
888
                }
800
889
                ++c;
801
890
            }
802
 
            if (except.isEmpty()) {
 
891
            if (!exceptions) 
803
892
                text << ".";
 
893
            else if (threadSafeness == Node::Reentrant) {
 
894
                if (nonreentrant.isEmpty()) {
 
895
                    if (!threadsafe.isEmpty()) {
 
896
                        text << ", but ";
 
897
                        appendFullNames(text,threadsafe,innerNode,marker);
 
898
                        singularPlural(text,threadsafe);
 
899
                        text << " also " << tlink << ".";
 
900
                    }
 
901
                    else
 
902
                        text << ".";
 
903
                }
 
904
                else {
 
905
                    text << ", except for ";
 
906
                    appendFullNames(text,nonreentrant,innerNode,marker);
 
907
                    text << ", which";
 
908
                    singularPlural(text,nonreentrant);
 
909
                    text << " nonreentrant.";
 
910
                    if (!threadsafe.isEmpty()) {
 
911
                        text << " ";
 
912
                        appendFullNames(text,threadsafe,innerNode,marker);
 
913
                        singularPlural(text,threadsafe);
 
914
                        text << " " << tlink << ".";
 
915
                    }
 
916
                }
804
917
            }
805
 
            else {
806
 
                text << ", except ";
807
 
 
808
 
                NodeList::ConstIterator e = except.begin();
809
 
                int index = 0;
810
 
                while (e != except.end()) {
811
 
                    appendFullName(text, *e, innerNode, marker);
812
 
                    text << separator(index++, except.count());
813
 
                    ++e;
 
918
            else { // thread-safe
 
919
                if (!nonreentrant.isEmpty() || !reentrant.isEmpty()) {
 
920
                    text << ", except for ";
 
921
                    if (!reentrant.isEmpty()) {
 
922
                        appendFullNames(text,reentrant,innerNode,marker);
 
923
                        text << ", which";
 
924
                        singularPlural(text,reentrant);
 
925
                        text << " only " << rlink;
 
926
                        if (!nonreentrant.isEmpty())
 
927
                            text << ", and ";
 
928
                    }
 
929
                    if (!nonreentrant.isEmpty()) {
 
930
                        appendFullNames(text,nonreentrant,innerNode,marker);
 
931
                        text << ", which";
 
932
                        singularPlural(text,nonreentrant);
 
933
                        text << " nonreentrant.";
 
934
                    }
 
935
                    text << ".";
814
936
                }
815
937
            }
816
938
        }
817
939
        else {
818
 
            text << "This " << typeString(node) << " is " << theStockLink << ".";
 
940
            text << "This " << typeString(node) << " is ";
 
941
            if (threadSafeness == Node::ThreadSafe)
 
942
                text << tlink;
 
943
            else
 
944
                text << rlink;
 
945
            text << ".";
819
946
        }
820
947
        text << Atom::ParaRight;
821
948
    }
822
 
    generateText(text, node, marker);
 
949
    generateText(text,node,marker);
823
950
}
824
951
 
825
952
void Generator::generateSince(const Node *node, CodeMarker *marker)
826
953
{
827
954
    if (!node->since().isEmpty()) {
828
955
        Text text;
829
 
        text << Atom::ParaLeft << "This " << typeString(node)
 
956
        text << Atom::ParaLeft
 
957
             << "This "
 
958
             << typeString(node)
830
959
             << " was introduced in ";
831
960
        if (project.isEmpty())
832
961
             text << "version";
856
985
{
857
986
    if (func->reimplementedFrom() != 0) {
858
987
        const FunctionNode *from = func->reimplementedFrom();
859
 
        if (from->access() != Node::Private && from->parent()->access() != Node::Private) {
 
988
        if (from->access() != Node::Private &&
 
989
            from->parent()->access() != Node::Private) {
860
990
            Text text;
861
991
            text << Atom::ParaLeft << "Reimplemented from ";
862
 
            appendFullName(text, from->parent(), func, marker, from);
 
992
            QString fullName =  from->parent()->name() + "::" + from->name() + "()";
 
993
            appendFullName(text, from->parent(), fullName, from);
863
994
            text << "." << Atom::ParaRight;
864
995
            generateText(text, func, marker);
865
996
        }
897
1028
 
898
1029
            if (atom->type() == Atom::FormatEndif) {
899
1030
                if (generate && numAtoms0 == numAtoms) {
900
 
                    relative->location().warning(tr("Output format %1 not handled").
901
 
                                                 arg(format()));
 
1031
                    relative->location().warning(tr("Output format %1 not handled")
 
1032
                                                 .arg(format()));
902
1033
                    Atom unhandledFormatAtom(Atom::UnhandledFormat, format());
903
1034
                    generateAtomList(&unhandledFormatAtom,
904
1035
                                     relative,
909
1040
                atom = atom->next();
910
1041
            }
911
1042
        }
912
 
        else if (atom->type() == Atom::FormatElse || atom->type() == Atom::FormatEndif) {
 
1043
        else if (atom->type() == Atom::FormatElse ||
 
1044
                 atom->type() == Atom::FormatEndif) {
913
1045
            return atom;
914
1046
        }
915
1047
        else {
939
1071
         << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
940
1072
}
941
1073
 
 
1074
void Generator::appendFullName(Text& text,
 
1075
                               const Node *apparentNode,
 
1076
                               const QString& fullName,
 
1077
                               const Node *actualNode)
 
1078
{
 
1079
    if (actualNode == 0)
 
1080
        actualNode = apparentNode;
 
1081
    text << Atom(Atom::LinkNode, CodeMarker::stringForNode(actualNode))
 
1082
         << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
 
1083
         << Atom(Atom::String, fullName)
 
1084
         << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
 
1085
}
 
1086
 
 
1087
void Generator::appendFullNames(Text& text,
 
1088
                                const NodeList& nodes,
 
1089
                                const Node* relative,
 
1090
                                CodeMarker* marker)
 
1091
{
 
1092
    NodeList::ConstIterator n = nodes.begin();
 
1093
    int index = 0;
 
1094
    while (n != nodes.end()) {
 
1095
        appendFullName(text,*n,relative,marker);
 
1096
        text << comma(index++,nodes.count());
 
1097
        ++n;
 
1098
    }
 
1099
}
 
1100
 
942
1101
void Generator::appendSortedNames(Text& text,
943
1102
                                  const ClassNode *classe,
944
1103
                                  const QList<RelatedClass> &classes,
950
1109
 
951
1110
    r = classes.begin();
952
1111
    while (r != classes.end()) {
953
 
        if ((*r).node->access() == Node::Public && (*r).node->status() != Node::Internal
 
1112
        if ((*r).node->access() == Node::Public &&
 
1113
            (*r).node->status() != Node::Internal
954
1114
            && !(*r).node->doc().isEmpty()) {
955
1115
            Text className;
956
1116
            appendFullName(className, (*r).node, classe, marker);