~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/tools/qdoc/qmlvisitor.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 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
#include <qfileinfo.h>
 
43
#include <qstringlist.h>
 
44
#include <qglobal.h>
 
45
#include "qqmljsast_p.h"
 
46
#include "qqmljsastfwd_p.h"
 
47
#include "qqmljsengine_p.h"
 
48
#include <qdebug.h>
 
49
#include "node.h"
 
50
#include "codeparser.h"
 
51
#include "qmlvisitor.h"
 
52
#include "qdocdatabase.h"
 
53
 
 
54
QT_BEGIN_NAMESPACE
 
55
 
 
56
#define COMMAND_DEPRECATED              Doc::alias(QLatin1String("deprecated"))
 
57
#define COMMAND_INGROUP                 Doc::alias(QLatin1String("ingroup"))
 
58
#define COMMAND_INTERNAL                Doc::alias(QLatin1String("internal"))
 
59
#define COMMAND_OBSOLETE                Doc::alias(QLatin1String("obsolete"))
 
60
#define COMMAND_PAGEKEYWORDS            Doc::alias(QLatin1String("pagekeywords"))
 
61
#define COMMAND_PRELIMINARY             Doc::alias(QLatin1String("preliminary"))
 
62
#define COMMAND_SINCE                   Doc::alias(QLatin1String("since"))
 
63
 
 
64
#define COMMAND_QMLABSTRACT             Doc::alias(QLatin1String("qmlabstract"))
 
65
#define COMMAND_QMLCLASS                Doc::alias(QLatin1String("qmlclass"))
 
66
#define COMMAND_QMLTYPE                 Doc::alias(QLatin1String("qmltype"))
 
67
#define COMMAND_QMLMODULE               Doc::alias(QLatin1String("qmlmodule"))
 
68
#define COMMAND_QMLPROPERTY             Doc::alias(QLatin1String("qmlproperty"))
 
69
#define COMMAND_QMLATTACHEDPROPERTY     Doc::alias(QLatin1String("qmlattachedproperty"))
 
70
#define COMMAND_QMLINHERITS             Doc::alias(QLatin1String("inherits"))
 
71
#define COMMAND_QMLINSTANTIATES         Doc::alias(QLatin1String("instantiates"))
 
72
#define COMMAND_INQMLMODULE             Doc::alias(QLatin1String("inqmlmodule"))
 
73
#define COMMAND_QMLSIGNAL               Doc::alias(QLatin1String("qmlsignal"))
 
74
#define COMMAND_QMLATTACHEDSIGNAL       Doc::alias(QLatin1String("qmlattachedsignal"))
 
75
#define COMMAND_QMLMETHOD               Doc::alias(QLatin1String("qmlmethod"))
 
76
#define COMMAND_QMLATTACHEDMETHOD       Doc::alias(QLatin1String("qmlattachedmethod"))
 
77
#define COMMAND_QMLDEFAULT              Doc::alias(QLatin1String("default"))
 
78
#define COMMAND_QMLREADONLY             Doc::alias(QLatin1String("readonly"))
 
79
#define COMMAND_QMLBASICTYPE            Doc::alias(QLatin1String("qmlbasictype"))
 
80
 
 
81
/*!
 
82
  The constructor stores all the parameters in local data members.
 
83
 */
 
84
QmlDocVisitor::QmlDocVisitor(const QString &filePath,
 
85
                             const QString &code,
 
86
                             QQmlJS::Engine *engine,
 
87
                             QSet<QString> &commands,
 
88
                             QSet<QString> &topics)
 
89
    : nestingLevel(0)
 
90
{
 
91
    this->filePath = filePath;
 
92
    this->name = QFileInfo(filePath).baseName();
 
93
    document = code;
 
94
    this->engine = engine;
 
95
    this->commands = commands;
 
96
    this->topics = topics;
 
97
    current = QDocDatabase::qdocDB()->treeRoot();
 
98
}
 
99
 
 
100
/*!
 
101
  The destructor does nothing.
 
102
 */
 
103
QmlDocVisitor::~QmlDocVisitor()
 
104
{
 
105
    // nothing.
 
106
}
 
107
 
 
108
/*!
 
109
  Returns the location of thre nearest comment above the \a offset.
 
110
 */
 
111
QQmlJS::AST::SourceLocation QmlDocVisitor::precedingComment(quint32 offset) const
 
112
{
 
113
    QListIterator<QQmlJS::AST::SourceLocation> it(engine->comments());
 
114
    it.toBack();
 
115
 
 
116
    while (it.hasPrevious()) {
 
117
 
 
118
        QQmlJS::AST::SourceLocation loc = it.previous();
 
119
 
 
120
        if (loc.begin() <= lastEndOffset)
 
121
            // Return if we reach the end of the preceding structure.
 
122
            break;
 
123
 
 
124
        else if (usedComments.contains(loc.begin()))
 
125
            // Return if we encounter a previously used comment.
 
126
            break;
 
127
 
 
128
        else if (loc.begin() > lastEndOffset && loc.end() < offset) {
 
129
 
 
130
            // Only examine multiline comments in order to avoid snippet markers.
 
131
            if (document.at(loc.offset - 1) == QLatin1Char('*')) {
 
132
                QString comment = document.mid(loc.offset, loc.length);
 
133
                if (comment.startsWith(QLatin1Char('!')) || comment.startsWith(QLatin1Char('*')))
 
134
                    return loc;
 
135
            }
 
136
        }
 
137
    }
 
138
 
 
139
    return QQmlJS::AST::SourceLocation();
 
140
}
 
141
 
 
142
/*!
 
143
  Finds the nearest unused qdoc comment above the QML entity
 
144
  represented by the \a node and processes the qdoc commands
 
145
  in that comment. The proceesed documentation is stored in
 
146
  the \a node.
 
147
 
 
148
  If a qdoc comment is found about \a location, true is returned.
 
149
  If a comment is not found there, false is returned.
 
150
 */
 
151
bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Node* node)
 
152
{
 
153
    QQmlJS::AST::SourceLocation loc = precedingComment(location.begin());
 
154
 
 
155
    if (loc.isValid()) {
 
156
        QString source = document.mid(loc.offset, loc.length);
 
157
        Location start(filePath);
 
158
        start.setLineNo(loc.startLine);
 
159
        start.setColumnNo(loc.startColumn);
 
160
        Location finish(filePath);
 
161
        finish.setLineNo(loc.startLine);
 
162
        finish.setColumnNo(loc.startColumn);
 
163
 
 
164
        Doc doc(start, finish, source.mid(1), commands, topics);
 
165
        node->setDoc(doc);
 
166
        applyMetacommands(loc, node, doc);
 
167
        usedComments.insert(loc.offset);
 
168
        if (doc.isEmpty())
 
169
            return false;
 
170
        return true;
 
171
    }
 
172
    Location codeLoc(filePath);
 
173
    codeLoc.setLineNo(location.startLine);
 
174
    node->setLocation(codeLoc);
 
175
    return false;
 
176
}
 
177
 
 
178
/*!
 
179
  A QML property argument has the form...
 
180
 
 
181
  <type> <component>::<name>
 
182
  <type> <QML-module>::<component>::<name>
 
183
 
 
184
  This function splits the argument into one of those
 
185
  two forms. The three part form is the old form, which
 
186
  was used before the creation of QtQuick 2 and Qt
 
187
  Components. A <QML-module> is the QML equivalent of a
 
188
  C++ namespace. So this function splits \a arg on "::"
 
189
  and stores the parts in the \e {type}, \e {module},
 
190
  \e {component}, and \a {name}, fields of \a qpa. If it
 
191
  is successful, it returns true. If not enough parts
 
192
  are found, a qdoc warning is emitted and false is
 
193
  returned.
 
194
 */
 
195
bool QmlDocVisitor::splitQmlPropertyArg(const Doc& doc,
 
196
                                        const QString& arg,
 
197
                                        QmlPropArgs& qpa)
 
198
{
 
199
    qpa.clear();
 
200
    QStringList blankSplit = arg.split(QLatin1Char(' '));
 
201
    if (blankSplit.size() > 1) {
 
202
        qpa.type_ = blankSplit[0];
 
203
        QStringList colonSplit(blankSplit[1].split("::"));
 
204
        if (colonSplit.size() == 3) {
 
205
            qpa.module_ = colonSplit[0];
 
206
            qpa.component_ = colonSplit[1];
 
207
            qpa.name_ = colonSplit[2];
 
208
            return true;
 
209
        }
 
210
        else if (colonSplit.size() == 2) {
 
211
            qpa.component_ = colonSplit[0];
 
212
            qpa.name_ = colonSplit[1];
 
213
            return true;
 
214
        }
 
215
        else if (colonSplit.size() == 1) {
 
216
            qpa.name_ = colonSplit[0];
 
217
            return true;
 
218
        }
 
219
        QString msg = "Unrecognizable QML module/component qualifier for " + arg;
 
220
        doc.location().warning(tr(msg.toLatin1().data()));
 
221
    }
 
222
    else {
 
223
        QString msg = "Missing property type for " + arg;
 
224
        doc.location().warning(tr(msg.toLatin1().data()));
 
225
    }
 
226
    return false;
 
227
}
 
228
 
 
229
/*!
 
230
  Applies the metacommands found in the comment.
 
231
 */
 
232
void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
 
233
                                      Node* node,
 
234
                                      Doc& doc)
 
235
{
 
236
    QDocDatabase* qdb = QDocDatabase::qdocDB();
 
237
 
 
238
    const TopicList& topicsUsed = doc.topicsUsed();
 
239
    if (topicsUsed.size() > 0) {
 
240
        if (node->type() == Node::QmlProperty) {
 
241
            QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
 
242
            for (int i=0; i<topicsUsed.size(); ++i) {
 
243
                if (topicsUsed.at(i).topic == "qmlproperty") {
 
244
                    QmlPropArgs qpa;
 
245
                    if (splitQmlPropertyArg(doc, topicsUsed.at(i).args, qpa)) {
 
246
                        QmlPropertyNode* n = new QmlPropertyNode(qpn, qpa.name_, qpa.type_, false);
 
247
                        n->setLocation(doc.location());
 
248
                        qpn->appendQmlPropNode(n);
 
249
                        n->setReadOnly(qpn->isReadOnly());
 
250
                        if (qpn->isDefault())
 
251
                            n->setDefault();
 
252
                    }
 
253
                    else
 
254
                        qDebug() << "  FAILED TO PARSE QML PROPERTY:"
 
255
                                 << topicsUsed.at(i).topic << topicsUsed.at(i).args;
 
256
                }
 
257
            }
 
258
        }
 
259
    }
 
260
    QSet<QString> metacommands = doc.metaCommandsUsed();
 
261
    if (metacommands.count() > 0) {
 
262
        QString topic;
 
263
        ArgList args;
 
264
        QSet<QString>::iterator i = metacommands.begin();
 
265
        while (i != metacommands.end()) {
 
266
            if (topics.contains(*i)) {
 
267
                topic = *i;
 
268
                break;
 
269
            }
 
270
            ++i;
 
271
        }
 
272
        if (!topic.isEmpty()) {
 
273
            args = doc.metaCommandArgs(topic);
 
274
            if ((topic == COMMAND_QMLCLASS) || (topic == COMMAND_QMLTYPE)) {
 
275
                // do nothing.
 
276
            }
 
277
            else if (topic == COMMAND_QMLPROPERTY) {
 
278
                if (node->type() == Node::QmlProperty) {
 
279
                    QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
 
280
                    qpn->setReadOnly(0);
 
281
                    if (qpn->dataType() == "alias") {
 
282
                        QStringList part = args[0].first.split(QLatin1Char(' '));
 
283
                        qpn->setDataType(part[0]);
 
284
                    }
 
285
                }
 
286
            }
 
287
            else if (topic == COMMAND_QMLMODULE) {
 
288
            }
 
289
            else if (topic == COMMAND_QMLATTACHEDPROPERTY) {
 
290
                if (node->type() == Node::QmlProperty) {
 
291
                    QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
 
292
                    qpn->setReadOnly(0);
 
293
                }
 
294
            }
 
295
            else if (topic == COMMAND_QMLSIGNAL) {
 
296
            }
 
297
            else if (topic == COMMAND_QMLATTACHEDSIGNAL) {
 
298
            }
 
299
            else if (topic == COMMAND_QMLMETHOD) {
 
300
            }
 
301
            else if (topic == COMMAND_QMLATTACHEDMETHOD) {
 
302
            }
 
303
            else if (topic == COMMAND_QMLBASICTYPE) {
 
304
            }
 
305
        }
 
306
        metacommands.subtract(topics);
 
307
        i = metacommands.begin();
 
308
        while (i != metacommands.end()) {
 
309
            QString command = *i;
 
310
            args = doc.metaCommandArgs(command);
 
311
            if (command == COMMAND_QMLABSTRACT) {
 
312
                if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) {
 
313
                    node->setAbstract(true);
 
314
                }
 
315
            }
 
316
            else if (command == COMMAND_DEPRECATED) {
 
317
                node->setStatus(Node::Deprecated);
 
318
            }
 
319
            else if (command == COMMAND_INQMLMODULE) {
 
320
                qdb->addToQmlModule(args[0].first,node);
 
321
            }
 
322
            else if (command == COMMAND_QMLINHERITS) {
 
323
                if (node->name() == args[0].first)
 
324
                    doc.location().warning(tr("%1 tries to inherit itself").arg(args[0].first));
 
325
                else {
 
326
                    CodeParser::setLink(node, Node::InheritsLink, args[0].first);
 
327
                    if (node->subType() == Node::QmlClass) {
 
328
                        QmlClassNode::addInheritedBy(args[0].first,node);
 
329
                    }
 
330
                }
 
331
            }
 
332
            else if (command == COMMAND_QMLDEFAULT) {
 
333
                if (node->type() == Node::QmlProperty) {
 
334
                    QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
 
335
                    qpn->setDefault();
 
336
                }
 
337
            }
 
338
            else if (command == COMMAND_QMLREADONLY) {
 
339
                if (node->type() == Node::QmlProperty) {
 
340
                    QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
 
341
                    qpn->setReadOnly(1);
 
342
                }
 
343
            }
 
344
            else if ((command == COMMAND_INGROUP) && !args.isEmpty()) {
 
345
                ArgList::ConstIterator argsIter = args.constBegin();
 
346
                while (argsIter != args.constEnd()) {
 
347
                    QDocDatabase::qdocDB()->addToGroup(argsIter->first, node);
 
348
                    ++argsIter;
 
349
                }
 
350
            }
 
351
            else if (command == COMMAND_INTERNAL) {
 
352
                node->setAccess(Node::Private);
 
353
                node->setStatus(Node::Internal);
 
354
            }
 
355
            else if (command == COMMAND_OBSOLETE) {
 
356
                if (node->status() != Node::Compat)
 
357
                    node->setStatus(Node::Obsolete);
 
358
            }
 
359
            else if (command == COMMAND_PAGEKEYWORDS) {
 
360
                // Not done yet. Do we need this?
 
361
            }
 
362
            else if (command == COMMAND_PRELIMINARY) {
 
363
                node->setStatus(Node::Preliminary);
 
364
            }
 
365
            else if (command == COMMAND_SINCE) {
 
366
                QString arg = args[0].first; //.join(' ');
 
367
                node->setSince(arg);
 
368
            }
 
369
            else {
 
370
                doc.location().warning(tr("The \\%1 command is ignored in QML files").arg(command));
 
371
            }
 
372
            ++i;
 
373
        }
 
374
    }
 
375
}
 
376
 
 
377
/*!
 
378
  Begin the visit of the object \a definition, recording it in the
 
379
  qdoc database. Increment the object nesting level, which is used
 
380
  to test whether we are at the public API level. The public level
 
381
  is level 1.
 
382
*/
 
383
bool QmlDocVisitor::visit(QQmlJS::AST::UiObjectDefinition *definition)
 
384
{
 
385
    QString type = definition->qualifiedTypeNameId->name.toString();
 
386
    nestingLevel++;
 
387
 
 
388
    if (current->type() == Node::Namespace) {
 
389
        QmlClassNode *component = new QmlClassNode(current, name);
 
390
        component->setTitle(name);
 
391
        component->setImportList(importList);
 
392
 
 
393
        if (applyDocumentation(definition->firstSourceLocation(), component)) {
 
394
            QmlClassNode::addInheritedBy(type, component);
 
395
            if (!component->links().contains(Node::InheritsLink))
 
396
                component->setLink(Node::InheritsLink, type, type);
 
397
        }
 
398
        current = component;
 
399
    }
 
400
 
 
401
    return true;
 
402
}
 
403
 
 
404
/*!
 
405
  End the visit of the object \a definition. In particular,
 
406
  decrement the object nesting level, which is used to test
 
407
  whether we are at the public API level. The public API
 
408
  level is level 1. It won't decrement below 0.
 
409
 */
 
410
void QmlDocVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *definition)
 
411
{
 
412
    if (nestingLevel > 0)
 
413
        --nestingLevel;
 
414
    lastEndOffset = definition->lastSourceLocation().end();
 
415
}
 
416
 
 
417
/*!
 
418
  Note that the imports list can be traversed by iteration to obtain
 
419
  all the imports in the document at once, having found just one:
 
420
 
 
421
  *it = imports; it; it = it->next
 
422
 
 
423
 */
 
424
bool QmlDocVisitor::visit(QQmlJS::AST::UiImportList *imports)
 
425
{
 
426
    QQmlJS::AST::UiImport* imp = imports->import;
 
427
    quint32 length =  imp->versionToken.offset - imp->fileNameToken.offset - 1;
 
428
    QString module = document.mid(imp->fileNameToken.offset,length);
 
429
    QString version = document.mid(imp->versionToken.offset, imp->versionToken.length);
 
430
    if (version.size() > 1) {
 
431
        int dot = version.lastIndexOf(QChar('.'));
 
432
        if (dot > 0)
 
433
            version = version.left(dot);
 
434
    }
 
435
    importList.append(QPair<QString, QString>(module, version));
 
436
 
 
437
    return true;
 
438
}
 
439
 
 
440
/*!
 
441
  End the visit of the imports list.
 
442
 */
 
443
void QmlDocVisitor::endVisit(QQmlJS::AST::UiImportList *definition)
 
444
{
 
445
    lastEndOffset = definition->lastSourceLocation().end();
 
446
}
 
447
 
 
448
/*!
 
449
    Visits the public \a member declaration, which can be a
 
450
    signal or a property. It is a custom signal or property.
 
451
    Only visit the \a member if the nestingLevel is 1.
 
452
*/
 
453
bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
 
454
{
 
455
    if (nestingLevel > 1)
 
456
        return true;
 
457
    switch (member->type) {
 
458
    case QQmlJS::AST::UiPublicMember::Signal:
 
459
    {
 
460
        if (current->type() == Node::Document) {
 
461
            QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
 
462
            if (qmlClass) {
 
463
 
 
464
                QString name = member->name.toString();
 
465
                FunctionNode *qmlSignal = new FunctionNode(Node::QmlSignal, current, name, false);
 
466
 
 
467
                QList<Parameter> parameters;
 
468
                for (QQmlJS::AST::UiParameterList *it = member->parameters; it; it = it->next) {
 
469
                    if (!it->type.isEmpty() && !it->name.isEmpty())
 
470
                        parameters.append(Parameter(it->type.toString(), QString(), it->name.toString()));
 
471
                }
 
472
 
 
473
                qmlSignal->setParameters(parameters);
 
474
                applyDocumentation(member->firstSourceLocation(), qmlSignal);
 
475
            }
 
476
        }
 
477
        break;
 
478
    }
 
479
    case QQmlJS::AST::UiPublicMember::Property:
 
480
    {
 
481
        QString type = member->memberType.toString();
 
482
        QString name = member->name.toString();
 
483
        if (current->type() == Node::Document) {
 
484
            QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
 
485
            if (qmlClass) {
 
486
                QString name = member->name.toString();
 
487
                QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlClass, name, type, false);
 
488
                qmlPropNode->setReadOnly(member->isReadonlyMember);
 
489
                if (member->isDefaultMember)
 
490
                    qmlPropNode->setDefault();
 
491
                applyDocumentation(member->firstSourceLocation(), qmlPropNode);
 
492
            }
 
493
        }
 
494
        break;
 
495
    }
 
496
    default:
 
497
        return false;
 
498
    }
 
499
 
 
500
    return true;
 
501
}
 
502
 
 
503
/*!
 
504
  End the visit of the \a member.
 
505
 */
 
506
void QmlDocVisitor::endVisit(QQmlJS::AST::UiPublicMember* member)
 
507
{
 
508
    lastEndOffset = member->lastSourceLocation().end();
 
509
}
 
510
 
 
511
bool QmlDocVisitor::visit(QQmlJS::AST::IdentifierPropertyName *)
 
512
{
 
513
    return true;
 
514
}
 
515
 
 
516
/*!
 
517
  Begin the visit of the function declaration \a fd, but only
 
518
  if the nesting level is 1.
 
519
 */
 
520
bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
 
521
{
 
522
    if (nestingLevel > 1)
 
523
        return true;
 
524
    if (current->type() == Node::Document) {
 
525
        QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);
 
526
        if (qmlClass) {
 
527
            QString name = fd->name.toString();
 
528
            FunctionNode* qmlMethod = new FunctionNode(Node::QmlMethod, current, name, false);
 
529
            int overloads = 0;
 
530
            NodeList::ConstIterator overloadIterator = current->childNodes().constBegin();
 
531
            while (overloadIterator != current->childNodes().constEnd()) {
 
532
                if ((*overloadIterator)->name() == name)
 
533
                    overloads++;
 
534
                overloadIterator++;
 
535
            }
 
536
            if (overloads > 1)
 
537
                qmlMethod->setOverload(true);
 
538
            QList<Parameter> parameters;
 
539
            QQmlJS::AST::FormalParameterList* formals = fd->formals;
 
540
            if (formals) {
 
541
                QQmlJS::AST::FormalParameterList* fpl = formals;
 
542
                do {
 
543
                    parameters.append(Parameter(QString(), QString(), fpl->name.toString()));
 
544
                    fpl = fpl->next;
 
545
                } while (fpl && fpl != formals);
 
546
                qmlMethod->setParameters(parameters);
 
547
            }
 
548
            applyDocumentation(fd->firstSourceLocation(), qmlMethod);
 
549
        }
 
550
    }
 
551
    return true;
 
552
}
 
553
 
 
554
/*!
 
555
  End the visit of the function declaration, \a fd.
 
556
 */
 
557
void QmlDocVisitor::endVisit(QQmlJS::AST::FunctionDeclaration* fd)
 
558
{
 
559
    lastEndOffset = fd->lastSourceLocation().end();
 
560
}
 
561
 
 
562
/*!
 
563
  Begin the visit of the signal handler declaration \a sb, but only
 
564
  if the nesting level is 1.
 
565
 */
 
566
bool QmlDocVisitor::visit(QQmlJS::AST::UiScriptBinding* sb)
 
567
{
 
568
    if (nestingLevel > 1)
 
569
        return true;
 
570
    if (current->type() == Node::Document) {
 
571
        QString handler = sb->qualifiedId->name.toString();
 
572
        if (handler.length() > 2 && handler.startsWith("on") && handler.at(2).isUpper()) {
 
573
            QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);
 
574
            if (qmlClass) {
 
575
                FunctionNode* qmlSH = new FunctionNode(Node::QmlSignalHandler,current,handler,false);
 
576
                applyDocumentation(sb->firstSourceLocation(), qmlSH);
 
577
            }
 
578
        }
 
579
    }
 
580
    return true;
 
581
}
 
582
 
 
583
void QmlDocVisitor::endVisit(QQmlJS::AST::UiScriptBinding* sb)
 
584
{
 
585
    lastEndOffset = sb->lastSourceLocation().end();
 
586
}
 
587
 
 
588
bool QmlDocVisitor::visit(QQmlJS::AST::UiQualifiedId* )
 
589
{
 
590
    return true;
 
591
}
 
592
 
 
593
void QmlDocVisitor::endVisit(QQmlJS::AST::UiQualifiedId* )
 
594
{
 
595
    // nothing.
 
596
}
 
597
 
 
598
QT_END_NAMESPACE