diff options
98 files changed, 1897 insertions, 1035 deletions
diff --git a/examples/uitools/multipleinheritance/main.cpp b/examples/uitools/multipleinheritance/main.cpp index c5febe60e..43b865fcd 100644 --- a/examples/uitools/multipleinheritance/main.cpp +++ b/examples/uitools/multipleinheritance/main.cpp @@ -46,11 +46,7 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); CalculatorForm calculator; -#if defined(Q_OS_SYMBIAN) - calculator.showMaximized(); -#else calculator.show(); -#endif return app.exec(); } //! [0] diff --git a/src/assistant/assistant/images/darkclosebutton.png b/src/assistant/assistant/images/darkclosebutton.png Binary files differindex 1077663b2..147a954be 100644 --- a/src/assistant/assistant/images/darkclosebutton.png +++ b/src/assistant/assistant/images/darkclosebutton.png diff --git a/src/assistant/assistant/stdinlistener.cpp b/src/assistant/assistant/stdinlistener.cpp index 13059c207..0a4241bce 100644 --- a/src/assistant/assistant/stdinlistener.cpp +++ b/src/assistant/assistant/stdinlistener.cpp @@ -35,6 +35,8 @@ #include "tracer.h" +#include <stdio.h> + QT_BEGIN_NAMESPACE StdInListener::StdInListener(QObject *parent) diff --git a/src/assistant/clucene/clucene.pro b/src/assistant/clucene/clucene.pro index 6eccfb1d7..8b8008b68 100644 --- a/src/assistant/clucene/clucene.pro +++ b/src/assistant/clucene/clucene.pro @@ -2,9 +2,6 @@ MODULE = clucene TARGET = QtCLucene QT = core -CONFIG += internal_module - -load(qt_module) include(fulltextsearch.pri) @@ -31,3 +28,6 @@ win32-msvc.net | win32-msvc2* | winrt-* | winphone-* { solaris* { DEFINES += Q_SOLARIS_VERSION=$$system(uname -r | sed -e 's/5\\.//') } + +CONFIG += internal_module +load(qt_module) diff --git a/src/assistant/help/help.pro b/src/assistant/help/help.pro index 168d23d30..37d5ba416 100644 --- a/src/assistant/help/help.pro +++ b/src/assistant/help/help.pro @@ -1,4 +1,5 @@ TARGET = QtHelp + QT = core-private gui widgets QT_PRIVATE = network sql clucene-private @@ -6,8 +7,6 @@ DEFINES += QHELP_LIB QT_CLUCENE_SUPPORT QMAKE_DOCS = $$PWD/doc/qthelp.qdocconf -load(qt_module) - DEFINES -= QT_ASCII_CAST_WARNINGS # impossible to disable exceptions in clucene atm and use help lib without @@ -59,3 +58,5 @@ HEADERS += qhelpenginecore.h \ # access to clucene HEADERS += qhelpsearchindexwriter_clucene_p.h \ qhelpsearchindexreader_clucene_p.h + +load(qt_module) diff --git a/src/assistant/help/qhelpcontentwidget.h b/src/assistant/help/qhelpcontentwidget.h index 43cd9b37b..2af6c022a 100644 --- a/src/assistant/help/qhelpcontentwidget.h +++ b/src/assistant/help/qhelpcontentwidget.h @@ -65,7 +65,7 @@ public: private: QHelpContentItem(const QString &name, const QString &link, - QHelpDBReader *reader, QHelpContentItem *parent = 0); + QHelpDBReader *reader, QHelpContentItem *parent = Q_NULLPTR); void appendChild(QHelpContentItem *child); QHelpContentItemPrivate *d; diff --git a/src/assistant/help/qhelpengine.h b/src/assistant/help/qhelpengine.h index c1b29654c..70216cc81 100644 --- a/src/assistant/help/qhelpengine.h +++ b/src/assistant/help/qhelpengine.h @@ -51,7 +51,7 @@ class QHELP_EXPORT QHelpEngine : public QHelpEngineCore Q_OBJECT public: - explicit QHelpEngine(const QString &collectionFile, QObject *parent = 0); + explicit QHelpEngine(const QString &collectionFile, QObject *parent = Q_NULLPTR); ~QHelpEngine(); QHelpContentModel *contentModel() const; diff --git a/src/assistant/help/qhelpenginecore.h b/src/assistant/help/qhelpenginecore.h index 9476ac273..8b7ee2cdb 100644 --- a/src/assistant/help/qhelpenginecore.h +++ b/src/assistant/help/qhelpenginecore.h @@ -54,7 +54,7 @@ class QHELP_EXPORT QHelpEngineCore : public QObject Q_PROPERTY(QString currentFilter READ currentFilter WRITE setCurrentFilter) public: - explicit QHelpEngineCore(const QString &collectionFile, QObject *parent = 0); + explicit QHelpEngineCore(const QString &collectionFile, QObject *parent = Q_NULLPTR); virtual ~QHelpEngineCore(); bool setupData(); diff --git a/src/assistant/help/qhelpprojectdata.cpp b/src/assistant/help/qhelpprojectdata.cpp index f48fdea9b..fa084ff3c 100644 --- a/src/assistant/help/qhelpprojectdata.cpp +++ b/src/assistant/help/qhelpprojectdata.cpp @@ -275,13 +275,13 @@ void QHelpProjectDataPrivate::addMatchingFiles(const QString &pattern) { // The pattern matching is expensive, so we skip it if no // wildcard symbols occur in the string. - if (!pattern.contains('?') && !pattern.contains('*') - && !pattern.contains('[') && !pattern.contains(']')) { + if (!pattern.contains(QLatin1Char('?')) && !pattern.contains(QLatin1Char('*')) + && !pattern.contains(QLatin1Char('[')) && !pattern.contains(QLatin1Char(']'))) { filterSectionList.last().addFile(pattern); return; } - QFileInfo fileInfo(rootPath + '/' + pattern); + QFileInfo fileInfo(rootPath + QLatin1Char('/') + pattern); const QDir &dir = fileInfo.dir(); const QString &path = dir.canonicalPath(); @@ -303,7 +303,7 @@ void QHelpProjectDataPrivate::addMatchingFiles(const QString &pattern) if (regExp.exactMatch(file)) { matchFound = true; filterSectionList.last(). - addFile(QFileInfo(pattern).dir().path() + '/' + file); + addFile(QFileInfo(pattern).dir().path() + QLatin1Char('/') + file); } } if (!matchFound) diff --git a/src/assistant/help/qhelpsearchengine.h b/src/assistant/help/qhelpsearchengine.h index 5baee49d0..314e91320 100644 --- a/src/assistant/help/qhelpsearchengine.h +++ b/src/assistant/help/qhelpsearchengine.h @@ -69,8 +69,7 @@ class QHELP_EXPORT QHelpSearchEngine : public QObject Q_OBJECT public: - explicit QHelpSearchEngine(QHelpEngineCore *helpEngine, - QObject *parent = 0); + explicit QHelpSearchEngine(QHelpEngineCore *helpEngine, QObject *parent = Q_NULLPTR); ~QHelpSearchEngine(); QHelpSearchQueryWidget* queryWidget(); diff --git a/src/assistant/help/qhelpsearchindexreader_clucene.cpp b/src/assistant/help/qhelpsearchindexreader_clucene.cpp index 18b128b01..a63128a88 100644 --- a/src/assistant/help/qhelpsearchindexreader_clucene.cpp +++ b/src/assistant/help/qhelpsearchindexreader_clucene.cpp @@ -270,8 +270,8 @@ bool QHelpSearchIndexReaderClucene::buildTryHarderQuery( bool QHelpSearchIndexReaderClucene::isNegativeQuery(const QHelpSearchQuery &query) const { - const QString &search = query.wordList.join(" "); - return search.contains('!') || search.contains('-') + const QString &search = query.wordList.join(QLatin1Char(' ')); + return search.contains(QLatin1Char('!')) || search.contains(QLatin1Char('-')) || search.contains(QLatin1String(" NOT ")); } diff --git a/src/assistant/help/qhelpsearchindexwriter_clucene.cpp b/src/assistant/help/qhelpsearchindexwriter_clucene.cpp index 96d46e0a4..f2a757f2e 100644 --- a/src/assistant/help/qhelpsearchindexwriter_clucene.cpp +++ b/src/assistant/help/qhelpsearchindexwriter_clucene.cpp @@ -331,6 +331,16 @@ static bool operator<(const QTextHtmlEntity &entity, const QString &entityStr) return QLatin1String(entity.name) < entityStr; } +static bool operator<(const QString &entityStr, const QTextHtmlEntity &entity) +{ + return entityStr < QLatin1String(entity.name); +} + +static bool operator<(const QTextHtmlEntity &entity, const QTextHtmlEntity &entity2) +{ + return QLatin1String(entity.name) < QLatin1String(entity2.name); +} + static QChar resolveEntity(const QString &entity) { const QTextHtmlEntity *start = &entities[0]; diff --git a/src/assistant/help/qhelpsearchquerywidget.cpp b/src/assistant/help/qhelpsearchquerywidget.cpp index 46f6fdfbd..e0b481e58 100644 --- a/src/assistant/help/qhelpsearchquerywidget.cpp +++ b/src/assistant/help/qhelpsearchquerywidget.cpp @@ -212,7 +212,7 @@ private: queryHist.queries.append(query); foreach (const QHelpSearchQuery &queryPart, query) { static_cast<CompleterModel *>(searchCompleter.model())-> - addTerm(queryPart.wordList.join(" ")); + addTerm(queryPart.wordList.join(QLatin1Char(' '))); } } } @@ -241,7 +241,7 @@ private: queryHist->queries.at(queryHist->curQuery); foreach (const QHelpSearchQuery &queryPart, query) { if (QLineEdit *lineEdit = lineEditFor(queryPart.fieldName)) - lineEdit->setText(queryPart.wordList.join(" ")); + lineEdit->setText(queryPart.wordList.join(QLatin1Char(' '))); } if (queryHist->curQuery == maxOrMinIndex) diff --git a/src/assistant/help/qhelpsearchquerywidget.h b/src/assistant/help/qhelpsearchquerywidget.h index 7e6b197c8..c771782b4 100644 --- a/src/assistant/help/qhelpsearchquerywidget.h +++ b/src/assistant/help/qhelpsearchquerywidget.h @@ -54,7 +54,7 @@ class QHELP_EXPORT QHelpSearchQueryWidget : public QWidget Q_OBJECT public: - QHelpSearchQueryWidget(QWidget *parent = 0); + explicit QHelpSearchQueryWidget(QWidget *parent = Q_NULLPTR); ~QHelpSearchQueryWidget(); void expandExtendedSearch(); diff --git a/src/designer/src/components/formeditor/formwindow.cpp b/src/designer/src/components/formeditor/formwindow.cpp index d51090553..3d09740ad 100644 --- a/src/designer/src/components/formeditor/formwindow.cpp +++ b/src/designer/src/components/formeditor/formwindow.cpp @@ -2182,8 +2182,6 @@ void FormWindow::layoutContainer(QWidget *w, int type) w = core()->widgetFactory()->containerOfWidget(w); const QObjectList l = w->children(); - if (l.isEmpty()) - return; // find managed widget children QWidgetList widgets; const QObjectList::const_iterator ocend = l.constEnd(); @@ -2194,6 +2192,9 @@ void FormWindow::layoutContainer(QWidget *w, int type) widgets.append(widget); } + if (widgets.isEmpty()) // QTBUG-50563, observed when using hand-edited forms. + return; + LayoutCommand *cmd = new LayoutCommand(this); cmd->init(mainContainer(), widgets, static_cast<LayoutInfo::Type>(type), w); clearSelection(false); diff --git a/src/designer/src/components/formeditor/formwindowmanager.cpp b/src/designer/src/components/formeditor/formwindowmanager.cpp index 386d09f8e..000c9d52f 100644 --- a/src/designer/src/components/formeditor/formwindowmanager.cpp +++ b/src/designer/src/components/formeditor/formwindowmanager.cpp @@ -363,7 +363,8 @@ QWidget *FormWindowManager::findManagedWidget(FormWindow *fw, QWidget *w) void FormWindowManager::setupActions() { #ifndef QT_NO_CLIPBOARD - m_actionCut = new QAction(createIconSet(QStringLiteral("editcut.png")), tr("Cu&t"), this); + const QIcon cutIcon = QIcon::fromTheme(QStringLiteral("edit-cut"), createIconSet(QStringLiteral("editcut.png"))); + m_actionCut = new QAction(cutIcon, tr("Cu&t"), this); m_actionCut->setObjectName(QStringLiteral("__qt_cut_action")); m_actionCut->setShortcut(QKeySequence::Cut); m_actionCut->setStatusTip(tr("Cuts the selected widgets and puts them on the clipboard")); @@ -371,7 +372,8 @@ void FormWindowManager::setupActions() connect(m_actionCut, &QAction::triggered, this, &FormWindowManager::slotActionCutActivated); m_actionCut->setEnabled(false); - m_actionCopy = new QAction(createIconSet(QStringLiteral("editcopy.png")), tr("&Copy"), this); + const QIcon copyIcon = QIcon::fromTheme(QStringLiteral("edit-copy"), createIconSet(QStringLiteral("editcopy.png"))); + m_actionCopy = new QAction(copyIcon, tr("&Copy"), this); m_actionCopy->setObjectName(QStringLiteral("__qt_copy_action")); m_actionCopy->setShortcut(QKeySequence::Copy); m_actionCopy->setStatusTip(tr("Copies the selected widgets to the clipboard")); @@ -379,7 +381,8 @@ void FormWindowManager::setupActions() connect(m_actionCopy, &QAction::triggered, this, &FormWindowManager::slotActionCopyActivated); m_actionCopy->setEnabled(false); - m_actionPaste = new QAction(createIconSet(QStringLiteral("editpaste.png")), tr("&Paste"), this); + const QIcon pasteIcon = QIcon::fromTheme(QStringLiteral("edit-paste"), createIconSet(QStringLiteral("editpaste.png"))); + m_actionPaste = new QAction(pasteIcon, tr("&Paste"), this); m_actionPaste->setObjectName(QStringLiteral("__qt_paste_action")); m_actionPaste->setShortcut(QKeySequence::Paste); m_actionPaste->setStatusTip(tr("Pastes the clipboard's contents")); @@ -388,7 +391,7 @@ void FormWindowManager::setupActions() m_actionPaste->setEnabled(false); #endif - m_actionDelete = new QAction(tr("&Delete"), this); + m_actionDelete = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), tr("&Delete"), this); m_actionDelete->setObjectName(QStringLiteral("__qt_delete_action")); m_actionDelete->setStatusTip(tr("Deletes the selected widgets")); m_actionDelete->setWhatsThis(whatsThisFrom(QStringLiteral("Edit|Delete"))); @@ -523,24 +526,6 @@ void FormWindowManager::setupActions() connect(m_actionShowFormWindowSettingsDialog, &QAction::triggered, this, &FormWindowManager::slotActionShowFormWindowSettingsDialog); m_actionShowFormWindowSettingsDialog->setEnabled(false); - -#if defined (Q_OS_UNIX) && !defined(Q_OS_MAC) -#ifndef QT_NO_CLIPBOARD - m_actionCopy->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"), m_actionCopy->icon())); - m_actionCut->setIcon(QIcon::fromTheme(QStringLiteral("edit-cut"), m_actionCut->icon())); - m_actionPaste->setIcon(QIcon::fromTheme(QStringLiteral("edit-paste"), m_actionPaste->icon())); -#endif - m_actionDelete->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"), m_actionDelete->icon())); - - // These do not currently exist, but will allow theme authors to fill in the gaps - m_actionBreakLayout->setIcon(QIcon::fromTheme(QStringLiteral("designer-break-layout"), m_actionBreakLayout->icon())); - m_actionGridLayout->setIcon(QIcon::fromTheme(QStringLiteral("designer-grid-layout"), m_actionGridLayout->icon())); - m_actionHorizontalLayout->setIcon(QIcon::fromTheme(QStringLiteral("designer-horizontal-layout"), m_actionHorizontalLayout->icon())); - m_actionVerticalLayout->setIcon(QIcon::fromTheme(QStringLiteral("designer-vertical-layout"), m_actionVerticalLayout->icon())); - m_actionSplitHorizontal->setIcon(QIcon::fromTheme(QStringLiteral("designer-split-horizontal"), m_actionSplitHorizontal->icon())); - m_actionSplitVertical->setIcon(QIcon::fromTheme(QStringLiteral("designer-split-vertical"), m_actionSplitVertical->icon())); - m_actionAdjustSize->setIcon(QIcon::fromTheme(QStringLiteral("designer-adjust-size"), m_actionAdjustSize->icon())); -#endif } #ifndef QT_NO_CLIPBOARD diff --git a/src/designer/src/components/formeditor/images/cleartext.png b/src/designer/src/components/formeditor/images/cleartext.png Binary files differindex 74133baff..4c7bb13f3 100644 --- a/src/designer/src/components/formeditor/images/cleartext.png +++ b/src/designer/src/components/formeditor/images/cleartext.png diff --git a/src/designer/src/components/formeditor/images/mac/simplifyrichtext.png b/src/designer/src/components/formeditor/images/mac/simplifyrichtext.png Binary files differindex a48e974bf..cdfc086bb 100644 --- a/src/designer/src/components/formeditor/images/mac/simplifyrichtext.png +++ b/src/designer/src/components/formeditor/images/mac/simplifyrichtext.png diff --git a/src/designer/src/components/formeditor/images/righttoleft.png b/src/designer/src/components/formeditor/images/righttoleft.png Binary files differindex 26a69d5ba..759066479 100644 --- a/src/designer/src/components/formeditor/images/righttoleft.png +++ b/src/designer/src/components/formeditor/images/righttoleft.png diff --git a/src/designer/src/components/lib/lib.pro b/src/designer/src/components/lib/lib.pro index b1e88e078..7b80ae130 100644 --- a/src/designer/src/components/lib/lib.pro +++ b/src/designer/src/components/lib/lib.pro @@ -1,11 +1,10 @@ -MODULE = designercomponents TARGET = QtDesignerComponents +MODULE = designercomponents + QT = core gui-private widgets-private designer-private QT_PRIVATE = xml CONFIG += internal_module -load(qt_module) - # QtDesignerComponents uses DEFINES += QT_STATICPLUGIN DEFINES += QDESIGNER_COMPONENTS_LIBRARY @@ -43,3 +42,5 @@ PRECOMPILED_HEADER= lib_pch.h # * MinGW-builds GCC 4.7.1 64-bit # * MinGW-w64 GCC 4.7.1 64-bit (rubenvb) mingw:CONFIG -= precompile_header + +load(qt_module) diff --git a/src/designer/src/designer/doc/images/designer-customize-toolbar.png b/src/designer/src/designer/doc/images/designer-customize-toolbar.png Binary files differindex 47bb533d9..3afecfed2 100644 --- a/src/designer/src/designer/doc/images/designer-customize-toolbar.png +++ b/src/designer/src/designer/doc/images/designer-customize-toolbar.png diff --git a/src/designer/src/designer/doc/images/designer-stylesheet-options.png b/src/designer/src/designer/doc/images/designer-stylesheet-options.png Binary files differindex 2fad456ff..98a4e5d67 100644 --- a/src/designer/src/designer/doc/images/designer-stylesheet-options.png +++ b/src/designer/src/designer/doc/images/designer-stylesheet-options.png diff --git a/src/designer/src/lib/extension/default_extensionfactory.h b/src/designer/src/lib/extension/default_extensionfactory.h index e43e6b3a2..669001f7e 100644 --- a/src/designer/src/lib/extension/default_extensionfactory.h +++ b/src/designer/src/lib/extension/default_extensionfactory.h @@ -50,7 +50,7 @@ class QDESIGNER_EXTENSION_EXPORT QExtensionFactory : public QObject, public QAbs Q_OBJECT Q_INTERFACES(QAbstractExtensionFactory) public: - QExtensionFactory(QExtensionManager *parent = 0); + explicit QExtensionFactory(QExtensionManager *parent = Q_NULLPTR); QObject *extension(QObject *object, const QString &iid) const Q_DECL_OVERRIDE; QExtensionManager *extensionManager() const; diff --git a/src/designer/src/lib/extension/extension.h b/src/designer/src/lib/extension/extension.h index f15b4415b..924bb9a1f 100644 --- a/src/designer/src/lib/extension/extension.h +++ b/src/designer/src/lib/extension/extension.h @@ -82,13 +82,13 @@ template <> inline IFace *qt_extension_helper<IFace *>(QAbstractExtensionManager template <class T> inline T qt_extension(QAbstractExtensionManager *, QObject *) -{ return 0; } +{ return Q_NULLPTR; } #define Q_DECLARE_EXTENSION_INTERFACE(IFace, IId) \ const char * const IFace##_iid = IId; \ Q_DECLARE_INTERFACE(IFace, IId) \ template <> inline IFace *qt_extension<IFace *>(QAbstractExtensionManager *manager, QObject *object) \ -{ QObject *extension = manager->extension(object, Q_TYPEID(IFace)); return extension ? static_cast<IFace *>(extension->qt_metacast(IFace##_iid)) : static_cast<IFace *>(0); } +{ QObject *extension = manager->extension(object, Q_TYPEID(IFace)); return extension ? static_cast<IFace *>(extension->qt_metacast(IFace##_iid)) : static_cast<IFace *>(Q_NULLPTR); } #endif diff --git a/src/designer/src/lib/extension/qextensionmanager.h b/src/designer/src/lib/extension/qextensionmanager.h index e0926aa6a..75fd741d5 100644 --- a/src/designer/src/lib/extension/qextensionmanager.h +++ b/src/designer/src/lib/extension/qextensionmanager.h @@ -47,7 +47,7 @@ class QDESIGNER_EXTENSION_EXPORT QExtensionManager: public QObject, public QAbst Q_OBJECT Q_INTERFACES(QAbstractExtensionManager) public: - QExtensionManager(QObject *parent = 0); + explicit QExtensionManager(QObject *parent = Q_NULLPTR); ~QExtensionManager(); void registerExtensions(QAbstractExtensionFactory *factory, const QString &iid = QString()) Q_DECL_OVERRIDE; diff --git a/src/designer/src/lib/lib.pro b/src/designer/src/lib/lib.pro index 2a597d0cf..de0dc7389 100644 --- a/src/designer/src/lib/lib.pro +++ b/src/designer/src/lib/lib.pro @@ -1,11 +1,8 @@ +TARGET = QtDesigner MODULE = designer -TARGET = QtDesigner QT = core-private gui-private widgets-private xml uiplugin -MODULE_PLUGIN_TYPES = designer -load(qt_module) - DEFINES += \ QDESIGNER_SDK_LIBRARY \ QDESIGNER_EXTENSION_LIBRARY \ @@ -19,3 +16,6 @@ include(sdk/sdk.pri) include(shared/shared.pri) include(uilib/uilib.pri) PRECOMPILED_HEADER=lib_pch.h + +MODULE_PLUGIN_TYPES = designer +load(qt_module) diff --git a/src/designer/src/lib/sdk/abstractactioneditor.h b/src/designer/src/lib/sdk/abstractactioneditor.h index 24a749e76..379360e2e 100644 --- a/src/designer/src/lib/sdk/abstractactioneditor.h +++ b/src/designer/src/lib/sdk/abstractactioneditor.h @@ -47,7 +47,7 @@ class QDESIGNER_SDK_EXPORT QDesignerActionEditorInterface: public QWidget { Q_OBJECT public: - QDesignerActionEditorInterface(QWidget *parent, Qt::WindowFlags flags = 0); + explicit QDesignerActionEditorInterface(QWidget *parent, Qt::WindowFlags flags = Qt::WindowFlags()); virtual ~QDesignerActionEditorInterface(); virtual QDesignerFormEditorInterface *core() const; diff --git a/src/designer/src/lib/sdk/abstractformeditor.h b/src/designer/src/lib/sdk/abstractformeditor.h index 35b222361..1b40819fc 100644 --- a/src/designer/src/lib/sdk/abstractformeditor.h +++ b/src/designer/src/lib/sdk/abstractformeditor.h @@ -70,7 +70,7 @@ class QDESIGNER_SDK_EXPORT QDesignerFormEditorInterface : public QObject { Q_OBJECT public: - QDesignerFormEditorInterface(QObject *parent = 0); + explicit QDesignerFormEditorInterface(QObject *parent = Q_NULLPTR); virtual ~QDesignerFormEditorInterface(); QExtensionManager *extensionManager() const; diff --git a/src/designer/src/lib/sdk/abstractformwindow.h b/src/designer/src/lib/sdk/abstractformwindow.h index d16173ddc..a95a19ef4 100644 --- a/src/designer/src/lib/sdk/abstractformwindow.h +++ b/src/designer/src/lib/sdk/abstractformwindow.h @@ -68,7 +68,7 @@ public: }; public: - QDesignerFormWindowInterface(QWidget *parent = 0, Qt::WindowFlags flags = 0); + explicit QDesignerFormWindowInterface(QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags()); virtual ~QDesignerFormWindowInterface(); virtual QString fileName() const = 0; @@ -76,7 +76,7 @@ public: virtual QString contents() const = 0; virtual QStringList checkContents() const = 0; - virtual bool setContents(QIODevice *dev, QString *errorMessage = 0) = 0; + virtual bool setContents(QIODevice *dev, QString *errorMessage = Q_NULLPTR) = 0; virtual Feature features() const = 0; virtual bool hasFeature(Feature f) const = 0; @@ -162,7 +162,7 @@ public Q_SLOTS: virtual bool setContents(const QString &contents) = 0; virtual void editWidgets() = 0; - void activateResourceFilePaths(const QStringList &paths, int *errorCount = 0, QString *errorMessages = 0); + void activateResourceFilePaths(const QStringList &paths, int *errorCount = Q_NULLPTR, QString *errorMessages = Q_NULLPTR); Q_SIGNALS: void mainContainerChanged(QWidget *mainContainer); diff --git a/src/designer/src/lib/sdk/abstractformwindowmanager.h b/src/designer/src/lib/sdk/abstractformwindowmanager.h index 7f7c5619c..cdcb1a88c 100644 --- a/src/designer/src/lib/sdk/abstractformwindowmanager.h +++ b/src/designer/src/lib/sdk/abstractformwindowmanager.h @@ -54,7 +54,7 @@ class QDESIGNER_SDK_EXPORT QDesignerFormWindowManagerInterface: public QObject { Q_OBJECT public: - explicit QDesignerFormWindowManagerInterface(QObject *parent = 0); + explicit QDesignerFormWindowManagerInterface(QObject *parent = Q_NULLPTR); virtual ~QDesignerFormWindowManagerInterface(); enum Action @@ -119,7 +119,7 @@ public: virtual int formWindowCount() const = 0; virtual QDesignerFormWindowInterface *formWindow(int index) const = 0; - virtual QDesignerFormWindowInterface *createFormWindow(QWidget *parentWidget = 0, Qt::WindowFlags flags = 0) = 0; + virtual QDesignerFormWindowInterface *createFormWindow(QWidget *parentWidget = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags()) = 0; virtual QDesignerFormEditorInterface *core() const = 0; diff --git a/src/designer/src/lib/sdk/abstractformwindowtool.h b/src/designer/src/lib/sdk/abstractformwindowtool.h index b596df32a..6f703142a 100644 --- a/src/designer/src/lib/sdk/abstractformwindowtool.h +++ b/src/designer/src/lib/sdk/abstractformwindowtool.h @@ -50,7 +50,7 @@ class QDESIGNER_SDK_EXPORT QDesignerFormWindowToolInterface: public QObject { Q_OBJECT public: - QDesignerFormWindowToolInterface(QObject *parent = 0); + explicit QDesignerFormWindowToolInterface(QObject *parent = Q_NULLPTR); virtual ~QDesignerFormWindowToolInterface(); virtual QDesignerFormEditorInterface *core() const = 0; diff --git a/src/designer/src/lib/sdk/abstractintegration.h b/src/designer/src/lib/sdk/abstractintegration.h index 0aef90db5..5627e4c3c 100644 --- a/src/designer/src/lib/sdk/abstractintegration.h +++ b/src/designer/src/lib/sdk/abstractintegration.h @@ -77,7 +77,7 @@ public: }; Q_DECLARE_FLAGS(Feature, FeatureFlag) - QDesignerIntegrationInterface(QDesignerFormEditorInterface *core, QObject *parent = 0); + explicit QDesignerIntegrationInterface(QDesignerFormEditorInterface *core, QObject *parent = Q_NULLPTR); virtual ~QDesignerIntegrationInterface(); QDesignerFormEditorInterface *core() const; @@ -85,7 +85,7 @@ public: virtual QWidget *containerWindow(QWidget *widget) const = 0; // Create a resource browser specific to integration. Language integration takes precedence - virtual QDesignerResourceBrowserInterface *createResourceBrowser(QWidget *parent = 0) = 0; + virtual QDesignerResourceBrowserInterface *createResourceBrowser(QWidget *parent = Q_NULLPTR) = 0; virtual QString headerSuffix() const = 0; virtual void setHeaderSuffix(const QString &headerSuffix) = 0; @@ -136,7 +136,7 @@ class QDESIGNER_SDK_EXPORT QDesignerIntegration: public QDesignerIntegrationInte { Q_OBJECT public: - explicit QDesignerIntegration(QDesignerFormEditorInterface *core, QObject *parent = 0); + explicit QDesignerIntegration(QDesignerFormEditorInterface *core, QObject *parent = Q_NULLPTR); virtual ~QDesignerIntegration(); QString headerSuffix() const; @@ -157,7 +157,7 @@ public: static void initializePlugins(QDesignerFormEditorInterface *formEditor); // Create a resource browser specific to integration. Language integration takes precedence - virtual QDesignerResourceBrowserInterface *createResourceBrowser(QWidget *parent = 0); + virtual QDesignerResourceBrowserInterface *createResourceBrowser(QWidget *parent = Q_NULLPTR); virtual QString contextHelpId() const; diff --git a/src/designer/src/lib/sdk/abstractlanguage.h b/src/designer/src/lib/sdk/abstractlanguage.h index b6a0b36de..66bbcce30 100644 --- a/src/designer/src/lib/sdk/abstractlanguage.h +++ b/src/designer/src/lib/sdk/abstractlanguage.h @@ -71,12 +71,12 @@ public: virtual QDialog *createFormWindowSettingsDialog(QDesignerFormWindowInterface *formWindow, QWidget *parentWidget) = 0; virtual QDesignerResourceBrowserInterface *createResourceBrowser(QWidget *parentWidget) = 0; - virtual QDialog *createPromotionDialog(QDesignerFormEditorInterface *formEditor, QWidget *parentWidget = 0) = 0; + virtual QDialog *createPromotionDialog(QDesignerFormEditorInterface *formEditor, QWidget *parentWidget = Q_NULLPTR) = 0; virtual QDialog *createPromotionDialog(QDesignerFormEditorInterface *formEditor, const QString &promotableWidgetClassName, QString *promoteToClassName, - QWidget *parentWidget = 0) = 0; + QWidget *parentWidget = Q_NULLPTR) = 0; virtual bool isLanguageResource(const QString &path) const = 0; diff --git a/src/designer/src/lib/sdk/abstractmetadatabase.h b/src/designer/src/lib/sdk/abstractmetadatabase.h index 08db94177..b2005c9d7 100644 --- a/src/designer/src/lib/sdk/abstractmetadatabase.h +++ b/src/designer/src/lib/sdk/abstractmetadatabase.h @@ -67,7 +67,7 @@ class QDESIGNER_SDK_EXPORT QDesignerMetaDataBaseInterface: public QObject { Q_OBJECT public: - QDesignerMetaDataBaseInterface(QObject *parent = 0); + explicit QDesignerMetaDataBaseInterface(QObject *parent = Q_NULLPTR); virtual ~QDesignerMetaDataBaseInterface(); virtual QDesignerMetaDataBaseItemInterface *item(QObject *object) const = 0; diff --git a/src/designer/src/lib/sdk/abstractnewformwidget.h b/src/designer/src/lib/sdk/abstractnewformwidget.h index 6db8d5120..65851a245 100644 --- a/src/designer/src/lib/sdk/abstractnewformwidget.h +++ b/src/designer/src/lib/sdk/abstractnewformwidget.h @@ -47,13 +47,13 @@ class QDESIGNER_SDK_EXPORT QDesignerNewFormWidgetInterface : public QWidget Q_DISABLE_COPY(QDesignerNewFormWidgetInterface) Q_OBJECT public: - explicit QDesignerNewFormWidgetInterface(QWidget *parent = 0); + explicit QDesignerNewFormWidgetInterface(QWidget *parent = Q_NULLPTR); virtual ~QDesignerNewFormWidgetInterface(); virtual bool hasCurrentTemplate() const = 0; - virtual QString currentTemplate(QString *errorMessage = 0) = 0; + virtual QString currentTemplate(QString *errorMessage = Q_NULLPTR) = 0; - static QDesignerNewFormWidgetInterface *createNewFormWidget(QDesignerFormEditorInterface *core, QWidget *parent = 0); + static QDesignerNewFormWidgetInterface *createNewFormWidget(QDesignerFormEditorInterface *core, QWidget *parent = Q_NULLPTR); Q_SIGNALS: void templateActivated(); diff --git a/src/designer/src/lib/sdk/abstractobjectinspector.h b/src/designer/src/lib/sdk/abstractobjectinspector.h index dcad701d6..b30df8a99 100644 --- a/src/designer/src/lib/sdk/abstractobjectinspector.h +++ b/src/designer/src/lib/sdk/abstractobjectinspector.h @@ -47,7 +47,7 @@ class QDESIGNER_SDK_EXPORT QDesignerObjectInspectorInterface: public QWidget { Q_OBJECT public: - QDesignerObjectInspectorInterface(QWidget *parent, Qt::WindowFlags flags = 0); + explicit QDesignerObjectInspectorInterface(QWidget *parent, Qt::WindowFlags flags = Qt::WindowFlags()); virtual ~QDesignerObjectInspectorInterface(); virtual QDesignerFormEditorInterface *core() const; diff --git a/src/designer/src/lib/sdk/abstractpropertyeditor.h b/src/designer/src/lib/sdk/abstractpropertyeditor.h index e01d2e7ad..70642dfd5 100644 --- a/src/designer/src/lib/sdk/abstractpropertyeditor.h +++ b/src/designer/src/lib/sdk/abstractpropertyeditor.h @@ -48,7 +48,7 @@ class QDESIGNER_SDK_EXPORT QDesignerPropertyEditorInterface: public QWidget { Q_OBJECT public: - QDesignerPropertyEditorInterface(QWidget *parent, Qt::WindowFlags flags = 0); + explicit QDesignerPropertyEditorInterface(QWidget *parent, Qt::WindowFlags flags = Qt::WindowFlags()); virtual ~QDesignerPropertyEditorInterface(); virtual QDesignerFormEditorInterface *core() const; diff --git a/src/designer/src/lib/sdk/abstractresourcebrowser.h b/src/designer/src/lib/sdk/abstractresourcebrowser.h index 12515d384..6e3c27ada 100644 --- a/src/designer/src/lib/sdk/abstractresourcebrowser.h +++ b/src/designer/src/lib/sdk/abstractresourcebrowser.h @@ -46,7 +46,7 @@ class QDESIGNER_SDK_EXPORT QDesignerResourceBrowserInterface: public QWidget { Q_OBJECT public: - QDesignerResourceBrowserInterface(QWidget *parent = 0); + explicit QDesignerResourceBrowserInterface(QWidget *parent = Q_NULLPTR); virtual ~QDesignerResourceBrowserInterface(); virtual void setCurrentPath(const QString &filePath) = 0; diff --git a/src/designer/src/lib/sdk/abstractwidgetbox.h b/src/designer/src/lib/sdk/abstractwidgetbox.h index 2ac4c6d91..a10351c9c 100644 --- a/src/designer/src/lib/sdk/abstractwidgetbox.h +++ b/src/designer/src/lib/sdk/abstractwidgetbox.h @@ -103,7 +103,7 @@ public: }; typedef QList<Category> CategoryList; - QDesignerWidgetBoxInterface(QWidget *parent = 0, Qt::WindowFlags flags = 0); + explicit QDesignerWidgetBoxInterface(QWidget *parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags()); virtual ~QDesignerWidgetBoxInterface(); virtual int categoryCount() const = 0; diff --git a/src/designer/src/lib/sdk/abstractwidgetdatabase.h b/src/designer/src/lib/sdk/abstractwidgetdatabase.h index 0a0ebaa12..4b3145d99 100644 --- a/src/designer/src/lib/sdk/abstractwidgetdatabase.h +++ b/src/designer/src/lib/sdk/abstractwidgetdatabase.h @@ -95,7 +95,7 @@ class QDESIGNER_SDK_EXPORT QDesignerWidgetDataBaseInterface: public QObject { Q_OBJECT public: - QDesignerWidgetDataBaseInterface(QObject *parent = 0); + explicit QDesignerWidgetDataBaseInterface(QObject *parent = Q_NULLPTR); virtual ~QDesignerWidgetDataBaseInterface(); virtual int count() const; diff --git a/src/designer/src/lib/sdk/abstractwidgetfactory.h b/src/designer/src/lib/sdk/abstractwidgetfactory.h index f87858087..419f6f67a 100644 --- a/src/designer/src/lib/sdk/abstractwidgetfactory.h +++ b/src/designer/src/lib/sdk/abstractwidgetfactory.h @@ -47,7 +47,7 @@ class QDESIGNER_SDK_EXPORT QDesignerWidgetFactoryInterface: public QObject { Q_OBJECT public: - QDesignerWidgetFactoryInterface(QObject *parent = 0); + explicit QDesignerWidgetFactoryInterface(QObject *parent = Q_NULLPTR); virtual ~QDesignerWidgetFactoryInterface(); virtual QDesignerFormEditorInterface *core() const = 0; @@ -55,7 +55,7 @@ public: virtual QWidget* containerOfWidget(QWidget *w) const = 0; virtual QWidget* widgetOfContainer(QWidget *w) const = 0; - virtual QWidget *createWidget(const QString &name, QWidget *parentWidget = 0) const = 0; + virtual QWidget *createWidget(const QString &name, QWidget *parentWidget = Q_NULLPTR) const = 0; virtual QLayout *createLayout(QWidget *widget, QLayout *layout, int type) const = 0; virtual bool isPassiveInteractor(QWidget *widget) = 0; diff --git a/src/designer/src/lib/sdk/taskmenu.h b/src/designer/src/lib/sdk/taskmenu.h index 16e7add58..c6b602fc0 100644 --- a/src/designer/src/lib/sdk/taskmenu.h +++ b/src/designer/src/lib/sdk/taskmenu.h @@ -53,7 +53,7 @@ Q_DECLARE_EXTENSION_INTERFACE(QDesignerTaskMenuExtension, "org.qt-project.Qt.Des inline QAction *QDesignerTaskMenuExtension::preferredEditAction() const -{ return 0; } +{ return Q_NULLPTR; } QT_END_NAMESPACE diff --git a/src/designer/src/lib/uilib/abstractformbuilder.h b/src/designer/src/lib/uilib/abstractformbuilder.h index e5e69edd7..764e4db66 100644 --- a/src/designer/src/lib/uilib/abstractformbuilder.h +++ b/src/designer/src/lib/uilib/abstractformbuilder.h @@ -107,7 +107,7 @@ public: QDir workingDirectory() const; void setWorkingDirectory(const QDir &directory); - virtual QWidget *load(QIODevice *dev, QWidget *parentWidget=0); + virtual QWidget *load(QIODevice *dev, QWidget *parentWidget = Q_NULLPTR); virtual void save(QIODevice *dev, QWidget *widget); QString errorString() const; diff --git a/src/designer/src/uitools/quiloader.h b/src/designer/src/uitools/quiloader.h index 7968e41d2..b7a8d7965 100644 --- a/src/designer/src/uitools/quiloader.h +++ b/src/designer/src/uitools/quiloader.h @@ -52,21 +52,21 @@ class QUiLoader : public QObject { Q_OBJECT public: - QUiLoader(QObject *parent = 0); + explicit QUiLoader(QObject *parent = Q_NULLPTR); virtual ~QUiLoader(); QStringList pluginPaths() const; void clearPluginPaths(); void addPluginPath(const QString &path); - QWidget *load(QIODevice *device, QWidget *parentWidget = 0); + QWidget *load(QIODevice *device, QWidget *parentWidget = Q_NULLPTR); QStringList availableWidgets() const; QStringList availableLayouts() const; - virtual QWidget *createWidget(const QString &className, QWidget *parent = 0, const QString &name = QString()); - virtual QLayout *createLayout(const QString &className, QObject *parent = 0, const QString &name = QString()); - virtual QActionGroup *createActionGroup(QObject *parent = 0, const QString &name = QString()); - virtual QAction *createAction(QObject *parent = 0, const QString &name = QString()); + virtual QWidget *createWidget(const QString &className, QWidget *parent = Q_NULLPTR, const QString &name = QString()); + virtual QLayout *createLayout(const QString &className, QObject *parent = Q_NULLPTR, const QString &name = QString()); + virtual QActionGroup *createActionGroup(QObject *parent = Q_NULLPTR, const QString &name = QString()); + virtual QAction *createAction(QObject *parent = Q_NULLPTR, const QString &name = QString()); void setWorkingDirectory(const QDir &dir); QDir workingDirectory() const; diff --git a/src/designer/src/uitools/uitools.pro b/src/designer/src/uitools/uitools.pro index b9e500080..8a71fa8b1 100644 --- a/src/designer/src/uitools/uitools.pro +++ b/src/designer/src/uitools/uitools.pro @@ -5,16 +5,16 @@ include(../lib/uilib/uilib.pri) QMAKE_DOCS = $$PWD/doc/qtuitools.qdocconf -# QtUiPlugins end up in designer for historical reasons. However, if -# designer isn't actually built, we need to claim the plugin type here. -!qtBuildPart(tools): \ - MODULE_PLUGIN_TYPES = designer - -load(qt_module) - HEADERS += quiloader.h SOURCES += quiloader.cpp DEFINES += \ QFORMINTERNAL_NAMESPACE \ QT_DESIGNER_STATIC + +# QtUiPlugins end up in designer for historical reasons. However, if +# designer isn't actually built, we need to claim the plugin type here. +!qtBuildPart(tools): \ + MODULE_PLUGIN_TYPES = designer + +load(qt_module) diff --git a/src/linguist/linguist/doc/images/linguist-auxlanguages.png b/src/linguist/linguist/doc/images/linguist-auxlanguages.png Binary files differindex 634605ed8..98727bbf2 100644 --- a/src/linguist/linguist/doc/images/linguist-auxlanguages.png +++ b/src/linguist/linguist/doc/images/linguist-auxlanguages.png diff --git a/src/linguist/linguist/doc/images/linguist-finddialog.png b/src/linguist/linguist/doc/images/linguist-finddialog.png Binary files differindex 831a3934e..d4949d243 100644 --- a/src/linguist/linguist/doc/images/linguist-finddialog.png +++ b/src/linguist/linguist/doc/images/linguist-finddialog.png diff --git a/src/linguist/lupdate/cpp.cpp b/src/linguist/lupdate/cpp.cpp index 0d5a7a8d9..37927c447 100644 --- a/src/linguist/lupdate/cpp.cpp +++ b/src/linguist/lupdate/cpp.cpp @@ -459,6 +459,7 @@ STRING(class); STRING(final); STRING(friend); STRING(namespace); +STRING(nullptr); STRING(operator); STRING(return); STRING(struct); @@ -698,6 +699,8 @@ CppParser::TokenType CppParser::getToken() case 'n': if (yyWord == strnamespace) return Tok_namespace; + if (yyWord == strnullptr) + return Tok_Null; break; case 'o': if (yyWord == stroperator) { diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp index 3cd98fc2c..35dd1402b 100644 --- a/src/macdeployqt/shared/shared.cpp +++ b/src/macdeployqt/shared/shared.cpp @@ -351,6 +351,19 @@ QStringList findAppFrameworkNames(const QString &appBundlePath) return frameworks; } +QStringList findAppFrameworkPaths(const QString &appBundlePath) +{ + QStringList frameworks; + QString searchPath = appBundlePath + "/Contents/Frameworks/"; + QDirIterator iter(searchPath, QStringList() << QString::fromLatin1("*.framework"), QDir::Dirs); + while (iter.hasNext()) { + iter.next(); + frameworks << iter.fileInfo().filePath(); + } + + return frameworks; +} + QStringList findAppLibraries(const QString &appBundlePath) { QStringList result; @@ -365,7 +378,7 @@ QStringList findAppLibraries(const QString &appBundlePath) return result; } -QStringList findAppBundleFiles(const QString &appBundlePath) +QStringList findAppBundleFiles(const QString &appBundlePath, bool absolutePath = false) { QStringList result; @@ -376,7 +389,7 @@ QStringList findAppBundleFiles(const QString &appBundlePath) iter.next(); if (iter.fileInfo().isSymLink()) continue; - result << iter.fileInfo().filePath(); + result << (absolutePath ? iter.fileInfo().absoluteFilePath() : iter.fileInfo().filePath()); } return result; @@ -498,7 +511,9 @@ QList<FrameworkInfo> getQtFrameworksForPaths(const QStringList &paths, const QSt return result; } -QStringList getBinaryDependencies(const QString executablePath, const QString &path) +QStringList getBinaryDependencies(const QString executablePath, + const QString &path, + const QList<QString> &additionalBinariesContainingRpaths) { QStringList binaries; @@ -527,6 +542,10 @@ QStringList getBinaryDependencies(const QString executablePath, const QString &p } else if (trimmedLine.startsWith("@rpath/")) { if (!rpathsLoaded) { rpaths = getBinaryRPaths(path, true, executablePath); + foreach (const QString &binaryPath, additionalBinariesContainingRpaths) { + QSet<QString> binaryRpaths = getBinaryRPaths(binaryPath, true); + rpaths += binaryRpaths; + } rpathsLoaded = true; } bool resolved = false; @@ -1004,7 +1023,6 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl } foreach (const QString &plugin, pluginList) { - QString sourcePath = pluginSourcePath + "/" + plugin; if (useDebugLibs) { // Use debug plugins if found. @@ -1019,10 +1037,8 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl if (copyFilePrintStatus(sourcePath, destinationPath)) { runStrip(destinationPath); - QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, appBundleInfo.path, deploymentInfo.rpathsUsed, useDebugLibs); deployQtFrameworks(frameworks, appBundleInfo.path, QStringList() << destinationPath, useDebugLibs, deploymentInfo.useLoaderPath); - } } } @@ -1241,7 +1257,7 @@ void codesignFile(const QString &identity, const QString &filePath) LogNormal() << "codesign" << filePath; QProcess codesign; - codesign.start("codesign", QStringList() << "--preserve-metadata=identifier,entitlements,resource-rules" + codesign.start("codesign", QStringList() << "--preserve-metadata=identifier,entitlements" << "--force" << "-s" << identity << filePath); codesign.waitForFinished(-1); @@ -1254,7 +1270,9 @@ void codesignFile(const QString &identity, const QString &filePath) } } -void codesign(const QString &identity, const QString &appBundlePath) +QSet<QString> codesignBundle(const QString &identity, + const QString &appBundlePath, + QList<QString> additionalBinariesContainingRpaths) { // Code sign all binaries in the app bundle. This needs to // be done inside-out, e.g sign framework dependencies @@ -1267,43 +1285,114 @@ void codesign(const QString &identity, const QString &appBundlePath) LogNormal() << "Signing" << appBundlePath << "with identity" << identity; QStack<QString> pendingBinaries; + QSet<QString> pendingBinariesSet; QSet<QString> signedBinaries; // Create the root code-binary set. This set consists of the application // executable(s) and the plugins. - QString rootBinariesPath = appBundlePath + "/Contents/MacOS/"; + QString appBundleAbsolutePath = QFileInfo(appBundlePath).absoluteFilePath(); + QString rootBinariesPath = appBundleAbsolutePath + "/Contents/MacOS/"; QStringList foundRootBinaries = QDir(rootBinariesPath).entryList(QStringList() << "*", QDir::Files); - foreach (const QString &binary, foundRootBinaries) - pendingBinaries.push(rootBinariesPath + binary); + foreach (const QString &binary, foundRootBinaries) { + QString binaryPath = rootBinariesPath + binary; + pendingBinaries.push(binaryPath); + pendingBinariesSet.insert(binaryPath); + additionalBinariesContainingRpaths.append(binaryPath); + } - QStringList foundPluginBinaries = findAppBundleFiles(appBundlePath + "/Contents/PlugIns/"); - foreach (const QString &binary, foundPluginBinaries) + bool getAbsoltuePath = true; + QStringList foundPluginBinaries = findAppBundleFiles(appBundlePath + "/Contents/PlugIns/", getAbsoltuePath); + foreach (const QString &binary, foundPluginBinaries) { pendingBinaries.push(binary); + pendingBinariesSet.insert(binary); + } + + // Add frameworks for processing. + QStringList frameworkPaths = findAppFrameworkPaths(appBundlePath); + foreach (const QString &frameworkPath, frameworkPaths) { + + // Add all files for a framework as a catch all. + QStringList bundleFiles = findAppBundleFiles(frameworkPath, getAbsoltuePath); + foreach (const QString &binary, bundleFiles) { + pendingBinaries.push(binary); + pendingBinariesSet.insert(binary); + } - QStringList foundLibraries = findAppBundleFiles(appBundlePath + "/Contents/Frameworks/"); - foreach (const QString &binary, foundLibraries) - pendingBinaries.push(binary); + // Prioritise first to sign any additional inner bundles found in the Helpers folder (e.g + // used by QtWebEngine). + QDirIterator helpersIterator(frameworkPath, QStringList() << QString::fromLatin1("Helpers"), QDir::Dirs | QDir::NoSymLinks, QDirIterator::Subdirectories); + while (helpersIterator.hasNext()) { + helpersIterator.next(); + QString helpersPath = helpersIterator.filePath(); + QStringList innerBundleNames = QDir(helpersPath).entryList(QStringList() << "*.app", QDir::Dirs); + foreach (const QString &innerBundleName, innerBundleNames) + signedBinaries += codesignBundle(identity, + helpersPath + "/" + innerBundleName, + additionalBinariesContainingRpaths); + } + // Also make sure to sign any libraries that will not be found by otool because they + // are not linked and won't be seen as a dependency. + QDirIterator librariesIterator(frameworkPath, QStringList() << QString::fromLatin1("Libraries"), QDir::Dirs | QDir::NoSymLinks, QDirIterator::Subdirectories); + while (librariesIterator.hasNext()) { + librariesIterator.next(); + QString librariesPath = librariesIterator.filePath(); + bundleFiles = findAppBundleFiles(librariesPath, getAbsoltuePath); + foreach (const QString &binary, bundleFiles) { + pendingBinaries.push(binary); + pendingBinariesSet.insert(binary); + } + } + } - // Sign all binares; use otool to find and sign dependencies first. + // Sign all binaries; use otool to find and sign dependencies first. while (!pendingBinaries.isEmpty()) { QString binary = pendingBinaries.pop(); if (signedBinaries.contains(binary)) continue; - // Check if there are unsigned dependencies, sign these first - QStringList dependencies = getBinaryDependencies(rootBinariesPath, binary).toSet().subtract(signedBinaries).toList(); + // Check if there are unsigned dependencies, sign these first. + QStringList dependencies = + getBinaryDependencies(rootBinariesPath, binary, additionalBinariesContainingRpaths).toSet() + .subtract(signedBinaries) + .subtract(pendingBinariesSet) + .toList(); + if (!dependencies.isEmpty()) { pendingBinaries.push(binary); - foreach (const QString &dependency, dependencies) + pendingBinariesSet.insert(binary); + int dependenciesSkipped = 0; + foreach (const QString &dependency, dependencies) { + // Skip dependencies that are outside the current app bundle, because this might + // cause a codesign error if the current bundle is part of the dependency (e.g. + // a bundle is part of a framework helper, and depends on that framework). + // The dependencies will be taken care of after the current bundle is signed. + if (!dependency.startsWith(appBundleAbsolutePath)) { + ++dependenciesSkipped; + LogNormal() << "Skipping outside dependency: " << dependency; + continue; + } pendingBinaries.push(dependency); - continue; + pendingBinariesSet.insert(dependency); + } + + // If all dependencies were skipped, make sure the binary is actually signed, instead + // of going into an infinite loop. + if (dependenciesSkipped == dependencies.size()) { + pendingBinaries.pop(); + } else { + continue; + } } - // All dependencies are signed, now sign this binary + + // All dependencies are signed, now sign this binary. codesignFile(identity, binary); signedBinaries.insert(binary); + pendingBinariesSet.remove(binary); } + LogNormal() << "Finished codesigning " << appBundlePath << "with identity" << identity; + // Verify code signature QProcess codesign; codesign.start("codesign", QStringList() << "--deep" << "-v" << appBundlePath); @@ -1315,6 +1404,12 @@ void codesign(const QString &identity, const QString &appBundlePath) } else if (!err.isEmpty()) { LogDebug() << err; } + + return signedBinaries; +} + +void codesign(const QString &identity, const QString &appBundlePath) { + codesignBundle(identity, appBundlePath, QList<QString>()); } void createDiskImage(const QString &appBundlePath) diff --git a/src/macdeployqt/shared/shared.h b/src/macdeployqt/shared/shared.h index d94033b54..4b4e9bed0 100644 --- a/src/macdeployqt/shared/shared.h +++ b/src/macdeployqt/shared/shared.h @@ -36,6 +36,7 @@ #include <QString> #include <QStringList> #include <QDebug> +#include <QSet> extern int logLevel; #define LogError() if (logLevel < 0) {} else qDebug() << "ERROR:" @@ -86,7 +87,6 @@ public: bool isFramework; }; - inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info); void changeQtFrameworks(const QString appPath, const QString &qtPath, bool useDebugLibs); @@ -108,7 +108,11 @@ void runStrip(const QString &binaryPath); void stripAppBinary(const QString &bundlePath); QString findAppBinary(const QString &appBundlePath); QStringList findAppFrameworkNames(const QString &appBundlePath); +QStringList findAppFrameworkPaths(const QString &appBundlePath); void codesignFile(const QString &identity, const QString &filePath); +QSet<QString> codesignBundle(const QString &identity, + const QString &appBundlePath, + QList<QString> additionalBinariesContainingRpaths); void codesign(const QString &identity, const QString &appBundlePath); void createDiskImage(const QString &appBundlePath); void fixupFramework(const QString &appBundlePath); diff --git a/src/qdoc/codemarker.cpp b/src/qdoc/codemarker.cpp index 3663d5009..366d2d8d2 100644 --- a/src/qdoc/codemarker.cpp +++ b/src/qdoc/codemarker.cpp @@ -368,10 +368,10 @@ QString CodeMarker::sortName(const Node *node, const QString* name) if (node->type() == Node::Function) { const FunctionNode *func = static_cast<const FunctionNode *>(node); QString sortNo; - if (func->metaness() == FunctionNode::Ctor) { + if (func->isSomeCtor()) { sortNo = QLatin1String("C"); } - else if (func->metaness() == FunctionNode::Dtor) { + else if (func->isDtor()) { sortNo = QLatin1String("D"); } else { @@ -424,16 +424,13 @@ void CodeMarker::insert(FastSection &fastSection, } else if (node->type() == Node::Function) { FunctionNode *func = (FunctionNode *) node; - irrelevant = (inheritedMember - && (func->metaness() == FunctionNode::Ctor || - func->metaness() == FunctionNode::Dtor)); + irrelevant = (inheritedMember && (func->isSomeCtor() || func->isDtor())); } - else if (node->type() == Node::Class || node->type() == Node::Enum - || node->type() == Node::Typedef) { + else if (node->isClass() || node->isEnumType() || node->isTypedef()) { irrelevant = (inheritedMember && style != Subpage); - if (!irrelevant && style == Detailed && node->type() == Node::Typedef) { - const TypedefNode* typedeffe = static_cast<const TypedefNode*>(node); - if (typedeffe->associatedEnum()) + if (!irrelevant && style == Detailed && node->isTypedef()) { + const TypedefNode* tdn = static_cast<const TypedefNode*>(node); + if (tdn->associatedEnum()) irrelevant = true; } } @@ -600,8 +597,7 @@ QStringList CodeMarker::macRefsForNode(Node *node) if (func->isOverload()) return QStringList(); - if (func->metaness() == FunctionNode::MacroWithParams - || func->metaness() == FunctionNode::MacroWithoutParams) { + if (func->isMacro()) { result += QLatin1String("macro/"); } else if (func->isStatic()) { @@ -660,7 +656,7 @@ QString CodeMarker::macName(const Node *node, const QString &name) /*! Returns an empty list of documentation sections. */ -QList<Section> CodeMarker::qmlSections(QmlTypeNode* , SynopsisStyle , Status ) +QList<Section> CodeMarker::qmlSections(Aggregate* , SynopsisStyle , Status ) { return QList<Section>(); } diff --git a/src/qdoc/codemarker.h b/src/qdoc/codemarker.h index 011c8623d..dd41813c6 100644 --- a/src/qdoc/codemarker.h +++ b/src/qdoc/codemarker.h @@ -146,7 +146,7 @@ public: virtual QList<Section> sections(const Aggregate *inner, SynopsisStyle style, Status status) = 0; - virtual QList<Section> qmlSections(QmlTypeNode* qmlTypeNode, + virtual QList<Section> qmlSections(Aggregate* aggregate, SynopsisStyle style, Status status = Okay); virtual QStringList macRefsForNode(Node* node); diff --git a/src/qdoc/cppcodemarker.cpp b/src/qdoc/cppcodemarker.cpp index b0e4e823d..c68012d2f 100644 --- a/src/qdoc/cppcodemarker.cpp +++ b/src/qdoc/cppcodemarker.cpp @@ -154,17 +154,19 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, if (style != Subpage && !func->returnType().isEmpty()) synopsis = typified(func->returnType(), true); synopsis += name; - if (func->metaness() != FunctionNode::MacroWithoutParams) { + if (!func->isMacroWithoutParams()) { synopsis += QLatin1Char('('); if (!func->parameters().isEmpty()) { QVector<Parameter>::ConstIterator p = func->parameters().constBegin(); while (p != func->parameters().constEnd()) { if (p != func->parameters().constBegin()) synopsis += ", "; - synopsis += typified((*p).dataType(), true); - if (style != Subpage && !(*p).name().isEmpty()) - synopsis += - "<@param>" + protect((*p).name()) + "</@param>"; + bool hasName = !(*p).name().isEmpty(); + if (hasName) + synopsis += typified((*p).dataType(), true); + const QString ¶mName = hasName ? (*p).name() : (*p).dataType(); + if (style != Subpage || !hasName) + synopsis += "<@param>" + protect(paramName) + "</@param>"; synopsis += protect((*p).rightType()); if (style != Subpage && !(*p).defaultValue().isEmpty()) synopsis += " = " + protect((*p).defaultValue()); @@ -177,10 +179,16 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, synopsis += " const"; if (style == Summary || style == Accessors) { - if (func->virtualness() != FunctionNode::NonVirtual) + if (!func->isNonvirtual()) synopsis.prepend("virtual "); - if (func->virtualness() == FunctionNode::PureVirtual) + if (func->isFinal()) + synopsis.append(" final"); + if (func->isPureVirtual()) synopsis.append(" = 0"); + else if (func->isDeleted()) + synopsis.append(" = delete"); + else if (func->isDefaulted()) + synopsis.append(" = default"); } else if (style == Subpage) { if (!func->returnType().isEmpty() && func->returnType() != "void") @@ -190,9 +198,14 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, QStringList bracketed; if (func->isStatic()) { bracketed += "static"; - } - else if (func->virtualness() != FunctionNode::NonVirtual) { - if (func->virtualness() == FunctionNode::PureVirtual) + } else if (func->isDeleted()) { + bracketed += "delete"; + } else if (func->isDefaulted()) { + bracketed += "default"; + } else if (!func->isNonvirtual()) { + if (func->isFinal()) + bracketed += "final"; + if (func->isPureVirtual()) bracketed += "pure"; bracketed += "virtual"; } @@ -204,10 +217,10 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, bracketed += "private"; } - if (func->metaness() == FunctionNode::Signal) { + if (func->isSignal()) { bracketed += "signal"; } - else if (func->metaness() == FunctionNode::Slot) { + else if (func->isSlot()) { bracketed += "slot"; } if (!bracketed.isEmpty()) @@ -331,9 +344,11 @@ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) while (p != func->parameters().constEnd()) { if (p != func->parameters().constBegin()) synopsis += ", "; - synopsis += typified((*p).dataType(), true); - if (!(*p).name().isEmpty()) - synopsis += "<@param>" + protect((*p).name()) + "</@param>"; + bool hasName = !(*p).name().isEmpty(); + if (hasName) + synopsis += typified((*p).dataType(), true); + const QString ¶mName = hasName ? (*p).name() : (*p).dataType(); + synopsis += "<@param>" + protect(paramName) + "</@param>"; synopsis += protect((*p).rightType()); ++p; } @@ -530,8 +545,8 @@ QList<Section> CppCodeMarker::sections(const Aggregate *inner, bool isStatic = false; if ((*c)->type() == Node::Function) { const FunctionNode *func = (const FunctionNode *) *c; - isSlot = (func->metaness() == FunctionNode::Slot); - isSignal = (func->metaness() == FunctionNode::Signal); + isSlot = (func->isSlot()); + isSignal = (func->isSignal()); isStatic = func->isStatic(); if (func->hasAssociatedProperties() && !func->hasActiveAssociatedProperty()) { ++c; @@ -1097,50 +1112,50 @@ QString CppCodeMarker::addMarkUp(const QString &in, /*! This function is for documenting QML properties. It returns the list of documentation sections for the children of the - \a qmlTypeNode. + \a aggregate. */ -QList<Section> CppCodeMarker::qmlSections(QmlTypeNode* qmlTypeNode, SynopsisStyle style, Status status) +QList<Section> CppCodeMarker::qmlSections(Aggregate* aggregate, SynopsisStyle style, Status status) { QList<Section> sections; - if (qmlTypeNode) { + if (aggregate) { if (style == Summary) { - FastSection qmlproperties(qmlTypeNode, + FastSection qmlproperties(aggregate, "Properties", QString(), "property", "properties"); - FastSection qmlattachedproperties(qmlTypeNode, + FastSection qmlattachedproperties(aggregate, "Attached Properties", QString(), "attached property", "attached properties"); - FastSection qmlsignals(qmlTypeNode, + FastSection qmlsignals(aggregate, "Signals", QString(), "signal", "signals"); - FastSection qmlsignalhandlers(qmlTypeNode, + FastSection qmlsignalhandlers(aggregate, "Signal Handlers", QString(), "signal handler", "signal handlers"); - FastSection qmlattachedsignals(qmlTypeNode, + FastSection qmlattachedsignals(aggregate, "Attached Signals", QString(), "attached signal", "attached signals"); - FastSection qmlmethods(qmlTypeNode, + FastSection qmlmethods(aggregate, "Methods", QString(), "method", "methods"); - FastSection qmlattachedmethods(qmlTypeNode, + FastSection qmlattachedmethods(aggregate, "Attached Methods", QString(), "attached method", "attached methods"); - QmlTypeNode* qcn = qmlTypeNode; + Aggregate* qcn = aggregate; while (qcn != 0) { NodeList::ConstIterator c = qcn->childNodes().constBegin(); while (c != qcn->childNodes().constEnd()) { @@ -1195,17 +1210,17 @@ QList<Section> CppCodeMarker::qmlSections(QmlTypeNode* qmlTypeNode, SynopsisStyl append(sections,qmlattachedmethods); } else if (style == Detailed) { - FastSection qmlproperties(qmlTypeNode, "Property Documentation","qmlprop","member","members"); - FastSection qmlattachedproperties(qmlTypeNode,"Attached Property Documentation","qmlattprop", + FastSection qmlproperties(aggregate, "Property Documentation","qmlprop","member","members"); + FastSection qmlattachedproperties(aggregate,"Attached Property Documentation","qmlattprop", "member","members"); - FastSection qmlsignals(qmlTypeNode,"Signal Documentation","qmlsig","signal","signals"); - FastSection qmlsignalhandlers(qmlTypeNode,"Signal Handler Documentation","qmlsighan","signal handler","signal handlers"); - FastSection qmlattachedsignals(qmlTypeNode,"Attached Signal Documentation","qmlattsig", + FastSection qmlsignals(aggregate,"Signal Documentation","qmlsig","signal","signals"); + FastSection qmlsignalhandlers(aggregate,"Signal Handler Documentation","qmlsighan","signal handler","signal handlers"); + FastSection qmlattachedsignals(aggregate,"Attached Signal Documentation","qmlattsig", "signal","signals"); - FastSection qmlmethods(qmlTypeNode,"Method Documentation","qmlmeth","member","members"); - FastSection qmlattachedmethods(qmlTypeNode,"Attached Method Documentation","qmlattmeth", + FastSection qmlmethods(aggregate,"Method Documentation","qmlmeth","member","members"); + FastSection qmlattachedmethods(aggregate,"Attached Method Documentation","qmlattmeth", "member","members"); - QmlTypeNode* qcn = qmlTypeNode; + Aggregate* qcn = aggregate; while (qcn != 0) { NodeList::ConstIterator c = qcn->childNodes().constBegin(); while (c != qcn->childNodes().constEnd()) { @@ -1264,8 +1279,8 @@ QList<Section> CppCodeMarker::qmlSections(QmlTypeNode* qmlTypeNode, SynopsisStyl members is prepared. */ ClassMap* classMap = 0; - FastSection all(qmlTypeNode,QString(),QString(),"member","members"); - QmlTypeNode* current = qmlTypeNode; + FastSection all(aggregate,QString(),QString(),"member","members"); + Aggregate* current = aggregate; while (current != 0) { /* If the QML type is abstract, do not create @@ -1280,7 +1295,7 @@ QList<Section> CppCodeMarker::qmlSections(QmlTypeNode* qmlTypeNode, SynopsisStyl */ if (!current->isAbstract() || !classMap) { classMap = new ClassMap; - classMap->first = current; + classMap->first = static_cast<const QmlTypeNode*>(current); all.classMapList_.append(classMap); } NodeList::ConstIterator c = current->childNodes().constBegin(); diff --git a/src/qdoc/cppcodemarker.h b/src/qdoc/cppcodemarker.h index aa759f299..67d2b07d9 100644 --- a/src/qdoc/cppcodemarker.h +++ b/src/qdoc/cppcodemarker.h @@ -70,7 +70,7 @@ public: virtual QList<Section> sections(const Aggregate *innerNode, SynopsisStyle style, Status status) Q_DECL_OVERRIDE; - virtual QList<Section> qmlSections(QmlTypeNode* qmlTypeNode, + virtual QList<Section> qmlSections(Aggregate* aggregate, SynopsisStyle style, Status status = Okay) Q_DECL_OVERRIDE; diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index 98800164f..c1295c3a7 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -316,80 +316,88 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, const QString& command, const ArgLocPair& arg) { + ExtraFuncData extra; if (command == COMMAND_FN) { - Declaration declData; - if (!parseDeclaration(arg.first, declData)) { - declData.clear(); - if (!parseDeclaration("void " + arg.first, declData)) { - doc.startLocation().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_FN)); - return 0; - } + QStringList parentPath; + FunctionNode *func = 0; + FunctionNode *clone = 0; + + if (!makeFunctionNode(arg.first, &parentPath, &clone, extra) && + !makeFunctionNode("void " + arg.first, &parentPath, &clone, extra)) { + doc.startLocation().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_FN)); } - FunctionNode* func = qdb_->findFunctionNode(declData.parentPath_, declData); - if (func == 0) { - if (declData.parentPath_.isEmpty() && !lastPath_.isEmpty()) { - func = qdb_->findFunctionNode(lastPath_, declData); + else { + func = qdb_->findFunctionNode(parentPath, clone); + if (func == 0) { + if (parentPath.isEmpty() && !lastPath_.isEmpty()) + func = qdb_->findFunctionNode(lastPath_, clone); } - } - /* - If the node was not found, then search for it in the - open C++ namespaces. We don't expect this search to - be necessary often. Nor do we expect it to succeed - very often. - */ - if (func == 0) - func = qdb_->findNodeInOpenNamespace(declData.parentPath_, declData); - - if (func == 0) { - doc.location().warning(tr("Cannot find '%1' in '\\%2' %3") - .arg(declData.name_ + "(...)") - .arg(COMMAND_FN) - .arg(arg.first), - tr("I cannot find any function of that name with the " - "specified signature. Make sure that the signature " - "is identical to the declaration, including 'const' " - "qualifiers.")); - } - else - lastPath_ = declData.parentPath_; - if (func) { - func->borrowParameterNames(declData); - func->setParentPath(declData.parentPath_); + + /* + If the node was not found, then search for it in the + open C++ namespaces. We don't expect this search to + be necessary often. Nor do we expect it to succeed + very often. + */ + if (func == 0) + func = qdb_->findNodeInOpenNamespace(parentPath, clone); + + if (func == 0) { + doc.location().warning(tr("Cannot find '%1' in '\\%2' %3") + .arg(clone->name() + "(...)") + .arg(COMMAND_FN) + .arg(arg.first), + tr("I cannot find any function of that name with the " + "specified signature. Make sure that the signature " + "is identical to the declaration, including 'const' " + "qualifiers.")); + } + else + lastPath_ = parentPath; + if (func) { + func->borrowParameterNames(clone); + func->setParentPath(clone->parentPath()); + } + delete clone; } return func; } else if (command == COMMAND_MACRO) { - FunctionNode* fn = 0; - Declaration declData(qdb_->primaryTreeRoot(), true); - if (parseDeclaration(arg.first, declData)) { - if (!declData.parentPath_.isEmpty()) { + QStringList parentPath; + FunctionNode *func = 0; + + extra.root = qdb_->primaryTreeRoot(); + extra.isMacro = true; + if (makeFunctionNode(arg.first, &parentPath, &func, extra)) { + if (!parentPath.isEmpty()) { doc.startLocation().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_MACRO)); + delete func; + func = 0; } - else if (declData.isFunction()) { - fn = createFunctionNode(declData); - fn->setMetaness(FunctionNode::MacroWithParams); - QVector<Parameter> params = fn->parameters(); + else { + func->setMetaness(FunctionNode::MacroWithParams); + QVector<Parameter> params = func->parameters(); for (int i = 0; i < params.size(); ++i) { Parameter ¶m = params[i]; if (param.name().isEmpty() && !param.dataType().isEmpty() && param.dataType() != "...") param = Parameter("", "", param.dataType()); } - fn->setParameters(params); + func->setParameters(params); } - return fn; + return func; } else if (QRegExp("[A-Za-z_][A-Za-z0-9_]+").exactMatch(arg.first)) { - fn = new FunctionNode(qdb_->primaryTreeRoot(), arg.first); - fn->setAccess(Node::Public); - fn->setLocation(doc.startLocation()); - fn->setMetaness(FunctionNode::MacroWithoutParams); + func = new FunctionNode(qdb_->primaryTreeRoot(), arg.first); + func->setAccess(Node::Public); + func->setLocation(doc.startLocation()); + func->setMetaness(FunctionNode::MacroWithoutParams); } else { doc.location().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_MACRO)); } - return fn; + return func; } else if (nodeTypeMap.contains(command)) { /* @@ -548,11 +556,13 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, (command == COMMAND_JSATTACHEDSIGNAL) || (command == COMMAND_JSATTACHEDMETHOD)) { QString module; - QString qmlTypeName; + QString name; QString type; - if (splitQmlMethodArg(arg.first, type, module, qmlTypeName)) { - QmlTypeNode* qmlType = qdb_->findQmlType(module, qmlTypeName); - if (qmlType) { + if (splitQmlMethodArg(arg.first, type, module, name)) { + Aggregate* aggregate = qdb_->findQmlType(module, name); + if (!aggregate) + aggregate = qdb_->findQmlBasicType(module, name); + if (aggregate) { bool attached = false; Node::NodeType nodeType = Node::QmlMethod; if ((command == COMMAND_QMLSIGNAL) || @@ -572,17 +582,12 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, attached = true; else return 0; // never get here. - FunctionNode* fn = 0; - Declaration declData(qmlType, nodeType, attached); - if (parseDeclaration(arg.first, declData)) { - fn = createFunctionNode(declData); - } - else { - Declaration declData(qmlType, nodeType, attached); - if (parseDeclaration("void " + arg.first, declData)) { - fn = createFunctionNode(declData); - } - } + FunctionNode* fn = makeFunctionNode(doc, + arg.first, + aggregate, + nodeType, + attached, + command); if (fn) { fn->setLocation(doc.startLocation()); if ((command == COMMAND_JSSIGNAL) || @@ -591,8 +596,6 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, (command == COMMAND_JSATTACHEDMETHOD)) fn->setGenus(Node::JS); } - else - doc.location().warning(tr("Invalid syntax in '\\%1'").arg(command)); return fn; } } @@ -810,9 +813,11 @@ void CppCodeParser::processQmlProperties(const Doc& doc, bool attached = ((topic == COMMAND_QMLATTACHEDPROPERTY) || (topic == COMMAND_JSATTACHEDPROPERTY)); if (splitQmlPropertyArg(arg, type, module, qmlTypeName, property)) { - qmlType = qdb_->findQmlType(module, qmlTypeName); - if (qmlType) { - if (qmlType->hasQmlProperty(property, attached) != 0) { + Aggregate* aggregate = qdb_->findQmlType(module, qmlTypeName); + if (!aggregate) + aggregate = qdb_->findQmlBasicType(module, qmlTypeName); + if (aggregate) { + if (aggregate->hasQmlProperty(property, attached) != 0) { QString msg = tr("QML property documented multiple times: '%1'").arg(arg); doc.startLocation().warning(msg); } @@ -823,7 +828,7 @@ void CppCodeParser::processQmlProperties(const Doc& doc, qpn->setGenus(Node::JS); } else { - qpn = new QmlPropertyNode(qmlType, property, type, attached); + qpn = new QmlPropertyNode(aggregate, property, type, attached); qpn->setLocation(doc.startLocation()); if (jsProps) qpn->setGenus(Node::JS); @@ -1046,7 +1051,7 @@ void CppCodeParser::reset() { tokenizer = 0; tok = 0; - access_ = Node::Public; + access = Node::Public; metaness_ = FunctionNode::Plain; lastPath_.clear(); physicalModuleName.clear(); @@ -1178,7 +1183,7 @@ bool CppCodeParser::matchTemplateHeader() return matchTemplateAngles(); } -bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) +bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var, bool qProp) { /* This code is really hard to follow... sorry. The loop is there to match @@ -1254,7 +1259,7 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) } while (match(Tok_Ampersand) || match(Tok_Aster) || match(Tok_const) || - match(Tok_Caret)) + match(Tok_Caret) || match(Tok_Ellipsis)) dataType->append(previousLexeme()); if (match(Tok_LeftParenAster)) { @@ -1304,6 +1309,10 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) if (varComment.exactMatch(previousLexeme())) *var = varComment.cap(1); } + else if (qProp && (match(Tok_default) || match(Tok_final))) { + // Hack to make 'default' and 'final' work again in Q_PROPERTY + *var = previousLexeme(); + } } if (tok == Tok_LeftBracket) { @@ -1384,308 +1393,322 @@ int CppCodeParser::matchFunctionModifier() return -1; } -bool CppCodeParser::matchDeclaration(Declaration& declData) +bool CppCodeParser::matchFunctionDecl(Aggregate *parent, + QStringList *parentPathPtr, + FunctionNode **funcPtr, + const QString &templateStuff, + ExtraFuncData& extra) { + CodeChunk returnType; + QStringList parentPath; + QString name; + + bool matched_QT_DEPRECATED = false; + bool matched_friend = false; + bool matched_static = false; + bool matched_inline = false; + bool matched_explicit = false; + bool matched_compat = false; + int token = tok; while (token != -1) { switch (token) { case Tok_friend: - declData.isFriend_ = true; + matched_friend = true; break; case Tok_inline: - declData.isInline_ = true; + matched_inline = true; break; case Tok_explicit: - declData.isExplicit_ = true; + matched_explicit = true; break; case Tok_static: - declData.isStatic_ = true; + matched_static = true; break; case Tok_QT_DEPRECATED: // no break here. - declData.isQT_DEPRECATED_ = true; + matched_QT_DEPRECATED = true; case Tok_QT_COMPAT: - declData.isCompat_ = true; + matched_compat = true; break; } token = matchFunctionModifier(); } - declData.virtuality_ = FunctionNode::NonVirtual; + FunctionNode::Virtualness virtuality = FunctionNode::NonVirtual; if (match(Tok_virtual)) { - declData.virtuality_ = FunctionNode::NormalVirtual; - if (!declData.isCompat_) - declData.isCompat_ = matchCompat(); + virtuality = FunctionNode::NormalVirtual; + if (!matched_compat) + matched_compat = matchCompat(); } - if (!matchDataType(&declData.returnType_)) { + if (!matchDataType(&returnType)) { if (tokenizer->parsingFnOrMacro() && (match(Tok_Q_DECLARE_FLAGS) || match(Tok_Q_PROPERTY) || match(Tok_Q_PRIVATE_PROPERTY))) - declData.returnType_ = CodeChunk(previousLexeme()); - else + returnType = CodeChunk(previousLexeme()); + else { return false; + } } - if (!declData.isCompat_) - declData.isCompat_ = matchCompat(); + if (returnType.toString() == "QBool") + returnType = CodeChunk("bool"); + + if (!matched_compat) + matched_compat = matchCompat(); if (tok == Tok_operator && - (declData.returnType_.toString().isEmpty() || - declData.returnType_.toString().endsWith("::"))) { + (returnType.toString().isEmpty() || + returnType.toString().endsWith("::"))) { // 'QString::operator const char *()' - declData.parentPath_ = declData.returnType_.toString().split(sep); - declData.parentPath_.removeAll(QString()); - declData.returnType_ = CodeChunk(); + parentPath = returnType.toString().split(sep); + parentPath.removeAll(QString()); + returnType = CodeChunk(); readToken(); CodeChunk restOfName; if (tok != Tok_Tilde && matchDataType(&restOfName)) { - declData.name_ = "operator " + restOfName.toString(); + name = "operator " + restOfName.toString(); } else { - declData.name_ = previousLexeme() + lexeme(); + name = previousLexeme() + lexeme(); readToken(); while (tok != Tok_LeftParen && tok != Tok_Eoi) { - declData.name_ += lexeme(); + name += lexeme(); readToken(); } } - if (tok != Tok_LeftParen) - return false; // This exit is never used. + if (tok != Tok_LeftParen) { + return false; + } } else if (tok == Tok_LeftParen) { // constructor or destructor - declData.parentPath_ = declData.returnType_.toString().split(sep); - if (!declData.parentPath_.isEmpty()) { - declData.name_ = declData.parentPath_.last(); - declData.parentPath_.erase(declData.parentPath_.end() - 1); + parentPath = returnType.toString().split(sep); + if (!parentPath.isEmpty()) { + name = parentPath.last(); + parentPath.erase(parentPath.end() - 1); } - declData.returnType_ = CodeChunk(); + returnType = CodeChunk(); } else { while (match(Tok_Ident)) { - declData.name_ = previousLexeme(); + name = previousLexeme(); /* This is a hack to let QML module identifiers through. */ - matchModuleQualifier(declData.name_); + matchModuleQualifier(name); matchTemplateAngles(); if (match(Tok_Gulbrandsen)) - declData.parentPath_.append(declData.name_); + parentPath.append(name); else break; } + if (tok == Tok_operator) { - declData.name_ = lexeme(); + name = lexeme(); readToken(); while (tok != Tok_Eoi) { - declData.name_ += lexeme(); + name += lexeme(); readToken(); if (tok == Tok_LeftParen) break; } } - if (declData.parent_ && (tok == Tok_Semicolon || - tok == Tok_LeftBracket || - tok == Tok_Colon) - && access_ == Node::Public) { - matchVariableDecl(declData); - return true; - } - if (tok != Tok_LeftParen) { - return false; // mws says these failures should be investigated. + if (parent && (tok == Tok_Semicolon || + tok == Tok_LeftBracket || + tok == Tok_Colon || tok == Tok_Equal) + && access != Node::Private) { + if (tok == Tok_LeftBracket) { + returnType.appendHotspot(); + + int bracketDepth0 = tokenizer->bracketDepth(); + while ((tokenizer->bracketDepth() >= bracketDepth0 && + tok != Tok_Eoi) || + tok == Tok_RightBracket) { + returnType.append(lexeme()); + readToken(); + } + if (tok != Tok_Semicolon) { + return false; + } + } + else if (tok == Tok_Colon || tok == Tok_Equal) { + returnType.appendHotspot(); + + while (tok != Tok_Semicolon && tok != Tok_Eoi) { + returnType.append(lexeme()); + readToken(); + } + if (tok != Tok_Semicolon) { + return false; + } + } + + VariableNode *var = new VariableNode(parent, name); + var->setAccess(access); + if (parsingHeaderFile_) + var->setLocation(declLoc()); + else + var->setLocation(location()); + var->setLeftType(returnType.left()); + var->setRightType(returnType.right()); + if (matched_compat) + var->setStatus(Node::Compat); + var->setStatic(matched_static); + return false; } + if (tok != Tok_LeftParen) + return false; } readToken(); - declData.location_ = location(); - declData.access_ = access_; - declData.metaness_ = metaness_; // A left paren was seen. Parse the parameters + bool isQPrivateSignal = false; + QVector<Parameter> pvect; if (tok != Tok_RightParen) { do { - if (!matchParameter(declData.pvect_, declData.isQPrivateSignal_)) - return false; // mws says these failures should be investigated. + if (!matchParameter(pvect, isQPrivateSignal)) + return false; } while (match(Tok_Comma)); } // The parameters must end with a right paren if (!match(Tok_RightParen)) - return false; // mws says these failures should be investigated. - - /* - When the right paren is matched, it might be the end without a semicolon. - e.g., if it is a macro. But there might be more for this declaration... - */ + return false; // look for const - declData.isConst_ = match(Tok_const); + bool matchedConst = match(Tok_const); + bool matchFinal = match(Tok_final); - if (match(Tok_throw)) { - if (match(Tok_LeftParen)) { - while (tok != Tok_RightParen && tok != Tok_Eoi) - readToken(); - if (tok != Tok_RightParen) - return false; - else - readToken(); - } - } - else - match(Tok_noexcept); - - // look for "= 0" indicating pure virtual - if (match(Tok_Equal) && match(Tok_Number)) - declData.virtuality_ = FunctionNode::PureVirtual; - - // look for ":" indicating ctors which must be skipped + bool isDeleted = false; + bool isDefaulted = false; + if (match(Tok_Equal)) { + if (match(Tok_Number)) // look for 0 indicating pure virtual + virtuality = FunctionNode::PureVirtual; + else if (match(Tok_delete)) + isDeleted = true; + else if (match(Tok_default)) + isDefaulted = true; + } + // look for colon indicating ctors which must be skipped if (match(Tok_Colon)) { while (tok != Tok_LeftBrace && tok != Tok_Eoi) readToken(); } // If no ';' expect a body, which must be skipped. + bool body_expected = false; + bool body_present = false; if (!match(Tok_Semicolon) && tok != Tok_Eoi) { - declData.bodyExpected_ = true; + body_expected = true; int nesting = tokenizer->braceDepth(); - if (!match(Tok_LeftBrace)) { - // It is correct for macro calls to return here. - return false; // mws says these failures should be investigated - } + if (!match(Tok_LeftBrace)) + return false; // skip the body while (tokenizer->braceDepth() >= nesting && tok != Tok_Eoi) readToken(); - declData.bodyPresent_ = true; + body_present = true; match(Tok_RightBrace); } + + FunctionNode *func = 0; + bool createFunctionNode = false; if (parsingHeaderFile_) { - if (declData.isFriend_) { - if (declData.isInline_) { + if (matched_friend) { + if (matched_inline) { // nothing yet } - if (declData.bodyPresent_) { - if (declData.bodyExpected_) { + if (body_present) { + if (body_expected) { // nothing yet } - if (declData.parent_ && declData.parent_->parent()) - declData.parent_ = declData.parent_->parent(); + createFunctionNode = true; + if (parent && parent->parent()) + parent = parent->parent(); else - return false; // This exit is never used. + return false; } } + else + createFunctionNode = true; } - declData.result_ = Function; - return true; -} - -/*! - This function creates a variable node from the data in \a declData. - This should be the only place where a variable node is created. - */ -VariableNode* CppCodeParser::createVariableNode(Declaration& declData) -{ - /* - Don't create a variable node if the access mode - is not public. - */ - VariableNode* var = 0; - if (declData.access_ == Node::Public) { - var = new VariableNode(declData.parent_, declData.name_); - var->setAccess(declData.access_); - var->setLocation(location()); - var->setLeftType(declData.returnType_.left()); - var->setRightType(declData.returnType_.right()); - if (declData.isCompat_) - var->setStatus(Node::Compat); - var->setStatic(declData.isStatic_); - } - return var; -} - -/*! - This function creates a function node from the data in \a declData. - This should be the only place where a function node is created. - */ -FunctionNode* CppCodeParser::createFunctionNode(Declaration& declData) -{ - FunctionNode* fn = new FunctionNode(declData.type_, declData.parent_, declData.name_, declData.isAttached_); - if (declData.isFriend_) - declData.access_ = Node::Public; - fn->setAccess(declData.access_); - fn->setLocation(declData.location_); - fn->setReturnType(declData.returnType_.toString()); - fn->setParentPath(declData.parentPath_); - fn->setTemplateStuff(declData.templateStuff_); - if (declData.isCompat_) - fn->setStatus(Node::Compat); - if (declData.isQT_DEPRECATED_) - fn->setStatus(Node::Deprecated); - if (declData.isExplicit_) { /* What can be done? */ } - fn->setMetaness(declData.metaness_); - if (declData.parent_) { - if (declData.name_ == declData.parent_->name()) - fn->setMetaness(FunctionNode::Ctor); - else if (declData.name_.startsWith(QLatin1Char('~'))) - fn->setMetaness(FunctionNode::Dtor); - } - fn->setStatic(declData.isStatic_); - fn->setConst(declData.isConst_); - fn->setVirtualness(declData.virtuality_); - if (declData.isQPrivateSignal_) - fn->setPrivateSignal(); - if (!declData.pvect_.isEmpty()) { - fn->setParameters(declData.pvect_); - } - return fn; -} - -/*! - Variable declarations get parsed by the same function that - parses function declarations, because variable declarations - look like function declarations until the end. As input, it - gets access to the data saved from parsing what it thought - was a function declaration in \a declData. - */ -void CppCodeParser::matchVariableDecl(Declaration& declData) -{ - if (tok == Tok_LeftBracket) { - declData.returnType_.appendHotspot(); - - int bracketDepth0 = tokenizer->bracketDepth(); - while ((tokenizer->bracketDepth() >= bracketDepth0 && - tok != Tok_Eoi) || - tok == Tok_RightBracket) { - declData.returnType_.append(lexeme()); - readToken(); - } - } - else if (tok == Tok_Colon) { - declData.returnType_.appendHotspot(); - - while (tok != Tok_Semicolon && tok != Tok_Eoi) { - declData.returnType_.append(lexeme()); - readToken(); - } - } - if (match(Tok_Equal)) { - int nesting = tokenizer->braceDepth(); - if (match(Tok_LeftBrace)) { - // skip the body - while (tokenizer->braceDepth() >= nesting && tok != Tok_Eoi) - readToken(); - } - while (tok != Tok_Semicolon && tok != Tok_Eoi) { - readToken(); - } - } - declData.access_ = access_; - - if (tok == Tok_Semicolon) - declData.result_ = Variable; else - declData.result_ = Ignore; + createFunctionNode = true; + + if (createFunctionNode) { + func = new FunctionNode(extra.type, parent, name, extra.isAttached); + if (matched_friend) + access = Node::Public; + func->setAccess(access); + if (parsingHeaderFile_) + func->setLocation(declLoc()); + else + func->setLocation(location()); + func->setReturnType(returnType.toString()); + func->setParentPath(parentPath); + func->setTemplateStuff(templateStuff); + if (matched_compat) + func->setStatus(Node::Compat); + if (matched_QT_DEPRECATED) + func->setStatus(Node::Deprecated); + if (matched_explicit) { /* What can be done? */ } + if (!pvect.isEmpty()) { + func->setParameters(pvect); + } + func->setMetaness(metaness_); + if (parent && (name == parent->name())) { + FunctionNode::Metaness m = FunctionNode::Ctor; + if (!pvect.isEmpty()) { + for (int i=0; i<pvect.size(); i++) { + const Parameter& p = pvect.at(i); + if (p.dataType().contains(name)) { + if (p.dataType().endsWith(QLatin1String("&&"))) { + m = FunctionNode::MCtor; + break; + } + if (p.dataType().endsWith(QLatin1String("&"))) { + m = FunctionNode::CCtor; + break; + } + } + } + } + func->setMetaness(m); + } + else if (name.startsWith(QLatin1Char('~'))) + func->setMetaness(FunctionNode::Dtor); + else if (name == QLatin1String("operator=")) { + FunctionNode::Metaness m = FunctionNode::Plain; + if (parent && pvect.size() == 1) { + const Parameter& p = pvect.at(0); + if (p.dataType().contains(parent->name())) { + if (p.dataType().endsWith(QLatin1String("&&"))) { + m = FunctionNode::MAssign; + } + else if (p.dataType().endsWith(QLatin1String("&"))) { + m = FunctionNode::CAssign; + } + } + } + func->setMetaness(m); + } + func->setStatic(matched_static); + func->setConst(matchedConst); + func->setVirtualness(virtuality); + func->setIsDeleted(isDeleted); + func->setIsDefaulted(isDefaulted); + func->setFinal(matchFinal); + if (isQPrivateSignal) + func->setPrivateSignal(); + } + if (parentPathPtr != 0) + *parentPathPtr = parentPath; + if (funcPtr != 0) + *funcPtr = func; + return true; } bool CppCodeParser::matchBaseSpecifier(ClassNode *classe, bool isClass) @@ -1763,6 +1786,9 @@ bool CppCodeParser::matchClassDecl(Aggregate *parent, } } } + + const QString className = previousLexeme(); + match(Tok_final); // ignore C++11 final class-virt-specifier if (tok != Tok_Colon && tok != Tok_LeftBrace) return false; @@ -1770,9 +1796,9 @@ bool CppCodeParser::matchClassDecl(Aggregate *parent, So far, so good. We have 'class Foo {' or 'class Foo :'. This is enough to recognize a class definition. */ - ClassNode *classe = new ClassNode(parent, previousLexeme()); - classe->setAccess(access_); - classe->setLocation(location()); + ClassNode *classe = new ClassNode(parent, className); + classe->setAccess(access); + classe->setLocation(declLoc()); if (compat) classe->setStatus(Node::Compat); if (!physicalModuleName.isEmpty()) @@ -1784,14 +1810,14 @@ bool CppCodeParser::matchClassDecl(Aggregate *parent, if (!match(Tok_LeftBrace)) return false; - Node::Access outerAccess = access_; - access_ = isClass ? Node::Private : Node::Public; + Node::Access outerAccess = access; + access = isClass ? Node::Private : Node::Public; FunctionNode::Metaness outerMetaness = metaness_; metaness_ = FunctionNode::Plain; bool matches = (matchDeclList(classe) && match(Tok_RightBrace) && match(Tok_Semicolon)); - access_ = outerAccess; + access = outerAccess; metaness_ = outerMetaness; return matches; } @@ -1815,8 +1841,8 @@ bool CppCodeParser::matchNamespaceDecl(Aggregate *parent) ns = static_cast<NamespaceNode*>(parent->findChildNode(namespaceName, Node::Namespace)); if (!ns) { ns = new NamespaceNode(parent, namespaceName); - ns->setAccess(access_); - ns->setLocation(location()); + ns->setAccess(access); + ns->setLocation(declLoc()); } readToken(); // skip '{' @@ -1897,7 +1923,7 @@ bool CppCodeParser::matchUsingDecl(Aggregate* parent) return true; } -bool CppCodeParser::matchEnumItem(Aggregate *parent, EnumNode* en) +bool CppCodeParser::matchEnumItem(Aggregate *parent, EnumNode *enume) { if (!match(Tok_Ident)) return false; @@ -1921,14 +1947,14 @@ bool CppCodeParser::matchEnumItem(Aggregate *parent, EnumNode* en) } } - if (en) { + if (enume) { QString strVal = val.toString(); if (strVal.isEmpty()) { - if (en->items().isEmpty()) { + if (enume->items().isEmpty()) { strVal = "0"; } else { - QString last = en->items().last().value(); + QString last = enume->items().last().value(); bool ok; int n = last.toInt(&ok); if (ok) { @@ -1944,11 +1970,11 @@ bool CppCodeParser::matchEnumItem(Aggregate *parent, EnumNode* en) } } - en->addItem(EnumItem(name, strVal)); + enume->addItem(EnumItem(name, strVal)); } else { VariableNode *var = new VariableNode(parent, name); - var->setAccess(access_); + var->setAccess(access); var->setLocation(location()); var->setLeftType("const int"); var->setStatic(true); @@ -1962,26 +1988,33 @@ bool CppCodeParser::matchEnumDecl(Aggregate *parent) if (!match(Tok_enum)) return false; + if (tok == Tok_struct || tok == Tok_class) + readToken(); // ignore C++11 struct or class attribute if (match(Tok_Ident)) name = previousLexeme(); + if (match(Tok_Colon)) { // ignore C++11 enum-base + CodeChunk dataType; + if (!matchDataType(&dataType)) + return false; + } if (tok != Tok_LeftBrace) return false; - EnumNode* en = 0; + EnumNode *enume = 0; if (!name.isEmpty()) { - en = new EnumNode(parent, name); - en->setAccess(access_); - en->setLocation(location()); + enume = new EnumNode(parent, name); + enume->setAccess(access); + enume->setLocation(declLoc()); } readToken(); - if (!matchEnumItem(parent, en)) + if (!matchEnumItem(parent, enume)) return false; while (match(Tok_Comma)) { - if (!matchEnumItem(parent, en)) + if (!matchEnumItem(parent, enume)) return false; } return match(Tok_RightBrace) && match(Tok_Semicolon); @@ -2001,8 +2034,8 @@ bool CppCodeParser::matchTypedefDecl(Aggregate *parent) if (parent && !parent->findChildNode(name, Node::Typedef)) { TypedefNode* td = new TypedefNode(parent, name); - td->setAccess(access_); - td->setLocation(location()); + td->setAccess(access); + td->setLocation(declLoc()); } return true; } @@ -2026,16 +2059,16 @@ bool CppCodeParser::matchProperty(Aggregate *parent) QString name; CodeChunk dataType; - if (!matchDataType(&dataType, &name)) + if (!matchDataType(&dataType, &name, true)) return false; PropertyNode *property = new PropertyNode(parent, name); property->setAccess(Node::Public); - property->setLocation(location()); + property->setLocation(declLoc()); property->setDataType(dataType.toString()); while (tok != Tok_RightParen && tok != Tok_Eoi) { - if (!match(Tok_Ident)) + if (!match(Tok_Ident) && !match(Tok_default) && !match(Tok_final)) return false; QString key = previousLexeme(); QString value; @@ -2122,6 +2155,7 @@ bool CppCodeParser::matchProperty(Aggregate *parent) */ bool CppCodeParser::matchDeclList(Aggregate *parent) { + ExtraFuncData extra; QString templateStuff; int braceDepth0 = tokenizer->braceDepth(); if (tok == Tok_RightBrace) // prevents failure on empty body @@ -2135,12 +2169,15 @@ bool CppCodeParser::matchDeclList(Aggregate *parent) case Tok_class: case Tok_struct: case Tok_union: + setDeclLoc(); matchClassDecl(parent, templateStuff); break; case Tok_namespace: + setDeclLoc(); matchNamespaceDecl(parent); break; case Tok_using: + setDeclLoc(); matchUsingDecl(parent); break; case Tok_template: @@ -2152,30 +2189,32 @@ bool CppCodeParser::matchDeclList(Aggregate *parent) } continue; case Tok_enum: + setDeclLoc(); matchEnumDecl(parent); break; case Tok_typedef: + setDeclLoc(); matchTypedefDecl(parent); break; case Tok_private: readToken(); - access_ = Node::Private; + access = Node::Private; metaness_ = FunctionNode::Plain; break; case Tok_protected: readToken(); - access_ = Node::Protected; + access = Node::Protected; metaness_ = FunctionNode::Plain; break; case Tok_public: readToken(); - access_ = Node::Public; + access = Node::Public; metaness_ = FunctionNode::Plain; break; case Tok_signals: case Tok_Q_SIGNALS: readToken(); - access_ = Node::Public; + access = Node::Public; metaness_ = FunctionNode::Signal; break; case Tok_slots: @@ -2190,6 +2229,7 @@ bool CppCodeParser::matchDeclList(Aggregate *parent) case Tok_Q_PROPERTY: case Tok_Q_PRIVATE_PROPERTY: case Tok_QDOC_PROPERTY: + setDeclLoc(); if (!matchProperty(parent)) { location().warning(tr("Failed to parse token %1 in property declaration").arg(lexeme())); skipTo(Tok_RightParen); @@ -2222,13 +2262,14 @@ bool CppCodeParser::matchDeclList(Aggregate *parent) break; case Tok_Q_DECLARE_FLAGS: readToken(); + setDeclLoc(); if (match(Tok_LeftParen) && match(Tok_Ident)) { QString flagsType = previousLexeme(); if (match(Tok_Comma) && match(Tok_Ident)) { QString name = previousLexeme(); TypedefNode *flagsNode = new TypedefNode(parent, flagsType); - flagsNode->setAccess(access_); - flagsNode->setLocation(location()); + flagsNode->setAccess(access); + flagsNode->setLocation(declLoc()); EnumNode* en = static_cast<EnumNode*>(parent->findChildNode(name, Node::Enum)); if (en) en->setFlagsType(flagsNode); @@ -2238,6 +2279,7 @@ bool CppCodeParser::matchDeclList(Aggregate *parent) break; case Tok_QT_MODULE: readToken(); + setDeclLoc(); if (match(Tok_LeftParen) && match(Tok_Ident)) physicalModuleName = previousLexeme(); if (!physicalModuleName.startsWith("Qt")) @@ -2245,19 +2287,9 @@ bool CppCodeParser::matchDeclList(Aggregate *parent) match(Tok_RightParen); break; default: - Declaration declData(parent, templateStuff); - if (matchDeclaration(declData)) { - if (declData.isFunction() && !declData.ignoreThisDecl()) - (void) createFunctionNode(declData); - else if (declData.isVariable()) { - /* - Always create the variable node because - we are parsing a .h file - */ - (void) createVariableNode(declData); - } - } - else { + if (parsingHeaderFile_) + setDeclLoc(); + if (!matchFunctionDecl(parent, 0, 0, templateStuff, extra)) { while (tok != Tok_Eoi && (tokenizer->braceDepth() > braceDepth0 || (!match(Tok_Semicolon) && @@ -2278,6 +2310,7 @@ bool CppCodeParser::matchDeclList(Aggregate *parent) */ bool CppCodeParser::matchDocsAndStuff() { + ExtraFuncData extra; const QSet<QString>& topicCommandsAllowed = topicCommands(); const QSet<QString>& otherMetacommandsAllowed = otherMetaCommands(); const QSet<QString>& metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed; @@ -2305,30 +2338,27 @@ bool CppCodeParser::matchDocsAndStuff() const TopicList& topics = doc.topicsUsed(); if (!topics.isEmpty()) { topic = topics[0].topic; - if (topic.startsWith("qml")) { - if ((topic == COMMAND_QMLPROPERTY) || - (topic == COMMAND_QMLPROPERTYGROUP) || - (topic == COMMAND_QMLATTACHEDPROPERTY)) { - isQmlPropertyTopic = true; - } + if ((topic == COMMAND_QMLPROPERTY) || + (topic == COMMAND_QMLPROPERTYGROUP) || + (topic == COMMAND_QMLATTACHEDPROPERTY)) { + isQmlPropertyTopic = true; } - else if (topic.startsWith("js")) { - if ((topic == COMMAND_JSPROPERTY) || - (topic == COMMAND_JSPROPERTYGROUP) || - (topic == COMMAND_JSATTACHEDPROPERTY)) { - isJsPropertyTopic = true; - } + else if ((topic == COMMAND_JSPROPERTY) || + (topic == COMMAND_JSPROPERTYGROUP) || + (topic == COMMAND_JSATTACHEDPROPERTY)) { + isJsPropertyTopic = true; } } NodeList nodes; DocList docs; if (topic.isEmpty()) { + QStringList parentPath; + FunctionNode *clone; FunctionNode *func = 0; - Declaration declData(qdb_->primaryTreeRoot()); - matchDeclaration(declData); - if (declData.isFunction()) { - func = qdb_->findFunctionNode(declData.parentPath_, declData); + + if (matchFunctionDecl(0, &parentPath, &clone, QString(), extra)) { + func = qdb_->findFunctionNode(parentPath, clone); /* If the node was not found, then search for it in the open C++ namespaces. We don't expect this search to @@ -2336,13 +2366,14 @@ bool CppCodeParser::matchDocsAndStuff() very often. */ if (func == 0) - func = qdb_->findNodeInOpenNamespace(declData.parentPath_, declData); + func = qdb_->findNodeInOpenNamespace(parentPath, clone); if (func) { - func->borrowParameterNames(declData); + func->borrowParameterNames(clone); nodes.append(func); docs.append(doc); } + delete clone; } else { doc.location().warning(tr("Cannot tie this documentation to anything"), @@ -2413,9 +2444,11 @@ bool CppCodeParser::matchDocsAndStuff() matchUsingDecl(0); } else { - Declaration declData(qdb_->primaryTreeRoot()); - matchDeclaration(declData); - if (declData.isFunction()) { + QStringList parentPath; + FunctionNode *clone; + FunctionNode *fnode = 0; + + if (matchFunctionDecl(0, &parentPath, &clone, QString(), extra)) { /* The location of the definition is more interesting than that of the declaration. People equipped with @@ -2425,9 +2458,10 @@ bool CppCodeParser::matchDocsAndStuff() Signals are implemented in uninteresting files generated by moc. */ - FunctionNode* node = qdb_->findFunctionNode(declData.parentPath_, declData); - if (node && node->metaness() != FunctionNode::Signal) - node->setLocation(declData.location_); + fnode = qdb_->findFunctionNode(parentPath, clone); + if (fnode != 0 && !fnode->isSignal()) + fnode->setLocation(clone->location()); + delete clone; } else { if (tok != Tok_Doc) @@ -2444,7 +2478,10 @@ bool CppCodeParser::matchDocsAndStuff() If a match is found, \a funcPtr is set to point to the matching node and true is returned. */ -bool CppCodeParser::parseDeclaration(const QString& signature, Declaration& declData) +bool CppCodeParser::makeFunctionNode(const QString& signature, + QStringList* parentPathPtr, + FunctionNode** funcPtr, + ExtraFuncData& extra) { Tokenizer* outerTokenizer = tokenizer; int outerTok = tok; @@ -2455,9 +2492,11 @@ bool CppCodeParser::parseDeclaration(const QString& signature, Declaration& decl tokenizer = &stringTokenizer; readToken(); - inMacroCommand_ = declData.isMacro_; - bool ok = matchDeclaration(declData); + inMacroCommand_ = extra.isMacro; + bool ok = matchFunctionDecl(extra.root, parentPathPtr, funcPtr, QString(), extra); inMacroCommand_ = false; + // potential memory leak with funcPtr + tokenizer = outerTokenizer; tok = outerTok; return ok; @@ -2491,6 +2530,34 @@ bool CppCodeParser::parseParameters(const QString& parameters, return true; } +/*! + Create a new FunctionNode for a QML method or signal, as + specified by \a type, as a child of \a parent. \a sig is + the complete signature, and if \a attached is true, the + method or signal is "attached". \a qdoctag is the text of + the \a type. + + \a parent is the QML class node. The QML module and QML + type names have already been consumed to find \a parent. + What remains in \a sig is the method signature. The method + must be a child of \a parent. + */ +FunctionNode* CppCodeParser::makeFunctionNode(const Doc& doc, + const QString& sig, + Aggregate* parent, + Node::NodeType type, + bool attached, + QString qdoctag) +{ + QStringList pp; + FunctionNode* fn = 0; + ExtraFuncData extra(parent, type, attached); + if (!makeFunctionNode(sig, &pp, &fn, extra) && !makeFunctionNode("void " + sig, &pp, &fn, extra)) { + doc.location().warning(tr("Invalid syntax in '\\%1'").arg(qdoctag)); + } + return fn; +} + void CppCodeParser::parseQiteratorDotH(const Location &location, const QString &filePath) { QFile file(filePath); diff --git a/src/qdoc/cppcodeparser.h b/src/qdoc/cppcodeparser.h index cc0b0f2fe..d3a5829e3 100644 --- a/src/qdoc/cppcodeparser.h +++ b/src/qdoc/cppcodeparser.h @@ -51,6 +51,16 @@ class CppCodeParser : public CodeParser { Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeParser) + struct ExtraFuncData { + Aggregate* root; // Used as the parent. + Node::NodeType type; // The node type: Function, etc. + bool isAttached; // If true, the method is attached. + bool isMacro; // If true, we are parsing a macro signature. + ExtraFuncData() : root(0), type(Node::Function), isAttached(false), isMacro(false) { } + ExtraFuncData(Aggregate* r, Node::NodeType t, bool a) + : root(r), type(t), isAttached(a), isMacro(false) { } + }; + public: CppCodeParser(); ~CppCodeParser(); @@ -66,6 +76,8 @@ public: virtual void doneParsingHeaderFiles() Q_DECL_OVERRIDE; virtual void doneParsingSourceFiles() Q_DECL_OVERRIDE; bool parseParameters(const QString& parameters, QVector<Parameter>& pvect, bool& isQPrivateSignal); + const Location& declLoc() const { return declLoc_; } + void setDeclLoc() { declLoc_ = location(); } protected: const QSet<QString>& topicCommands(); @@ -107,9 +119,13 @@ protected: bool matchModuleQualifier(QString& name); bool matchTemplateAngles(CodeChunk *type = 0); bool matchTemplateHeader(); - bool matchDataType(CodeChunk *type, QString *var = 0); + bool matchDataType(CodeChunk *type, QString *var = 0, bool qProp = false); bool matchParameter(QVector<Parameter>& pvect, bool& isQPrivateSignal); - bool matchDeclaration(Declaration& declData); + bool matchFunctionDecl(Aggregate *parent, + QStringList *parentPathPtr, + FunctionNode **funcPtr, + const QString &templateStuff, + ExtraFuncData& extra); bool matchBaseSpecifier(ClassNode *classe, bool isClass); bool matchBaseList(ClassNode *classe, bool isClass); bool matchClassDecl(Aggregate *parent, @@ -122,27 +138,34 @@ protected: bool matchProperty(Aggregate *parent); bool matchDeclList(Aggregate *parent); bool matchDocsAndStuff(); - bool parseDeclaration(const QString &synopsis, Declaration& declData); + bool makeFunctionNode(const QString &synopsis, + QStringList *parentPathPtr, + FunctionNode **funcPtr, + ExtraFuncData& params); + FunctionNode* makeFunctionNode(const Doc& doc, + const QString& sig, + Aggregate* parent, + Node::NodeType type, + bool attached, + QString qdoctag); void parseQiteratorDotH(const Location &location, const QString &filePath); void instantiateIteratorMacro(const QString &container, const QString &includeFile, const QString ¯oDef); void createExampleFileNodes(DocumentNode *dn); - FunctionNode* createFunctionNode(Declaration& declData); - VariableNode* createVariableNode(Declaration& declData); int matchFunctionModifier(); - void matchVariableDecl(Declaration& declData); protected: QMap<QString, Node::NodeType> nodeTypeMap; Tokenizer *tokenizer; int tok; - Node::Access access_; + Node::Access access; FunctionNode::Metaness metaness_; QString physicalModuleName; QStringList lastPath_; QRegExp varComment; QRegExp sep; + Location declLoc_; private: QString sequentialIteratorDefinition; diff --git a/src/qdoc/doc.cpp b/src/qdoc/doc.cpp index b8fd5f931..412c1950e 100644 --- a/src/qdoc/doc.cpp +++ b/src/qdoc/doc.cpp @@ -1487,6 +1487,18 @@ void DocParser::parse(const QString& source, } } break; + // Do not parse content after '//!' comments + case '/': + { + if (pos + 2 < len) + if (in.at(pos + 1) == '/') + if (in.at(pos + 2) == '!') { + pos += 2; + getRestOfLine(); + break; + } + // fall through + } default: { bool newWord; diff --git a/src/qdoc/doc/qdoc-guide/qdoc-guide.qdoc b/src/qdoc/doc/qdoc-guide/qdoc-guide.qdoc index af1fa1ba1..5ca9174b0 100644 --- a/src/qdoc/doc/qdoc-guide/qdoc-guide.qdoc +++ b/src/qdoc/doc/qdoc-guide/qdoc-guide.qdoc @@ -267,10 +267,14 @@ \section1 QDoc Comments - Documentation is contained within qdoc \e comments, delimited by + Documentation is contained within QDoc \e comments, delimited by \beginqdoc and \endqdoc comments. Note that these are valid comments in C++, QML, and JavaScript. + Within a QDoc comment, \c {//!} is used as a single-line documentation + comment; the comment itself and anything after it, until a newline, + is omitted from the generated output. + QDoc will parse C++ and QML files to look for qdoc comments. To explicitly omit a certain file type, omit it from the \l{Input and Output Directories}{configuration} file. diff --git a/src/qdoc/doc/qdoc-manual-markupcmds.qdoc b/src/qdoc/doc/qdoc-manual-markupcmds.qdoc index 8a682affe..3992dc58e 100644 --- a/src/qdoc/doc/qdoc-manual-markupcmds.qdoc +++ b/src/qdoc/doc/qdoc-manual-markupcmds.qdoc @@ -1934,7 +1934,7 @@ \c {\l [QML|CPP|DOC|QtModuleName] {link target} {link text}} \endlist - The \e {square bracket} argument is only allowed in the \c {\\l + The \e {square bracket} argument is only allowed in the \c {\l (link)} command. The example above shows how \c QML is used as the \e {square brackets} argument to force qdoc to match a QML target. Most often, this will be a QML type, but it can also be a QML @@ -3775,17 +3775,20 @@ The \\include command sends all or part of the file specified by its first argument to the QDoc input stream to be processed as a - QDoc comment snippet. This command is often assigned the alias, - \e {input}, in the QDoc configuration file, for example \e {alias.include - = input}. - - The command is useful when some snippet of commands and text is to - be used in multiple places in the documentation. In that case, - move the snippet into a separate file and use the \\include - command wherever you want to insert the snippet into the - documentation. To prevent QDoc from reading the file as a - stand-alone page of documentation, we recommend that you use the - \c .qdocinc extension for these \e {include} files. + QDoc comment snippet. + + The command is useful when some snippet of commands or text is to + be used in multiple places in the documentation. Use the \\include + command wherever you want to insert a snippet into the documentation. + The file containing the snippet to include must be located under the + path(s) listed in the \l{sourcedirs-variable}{sourcedirs} QDoc + configuration variable. It can be either any source file parsed + by QDoc (or even the same one where \\include command is used), or + any other text file. To store snippets in a separate file that is + not meant to be parsed by QDoc, use a file extension that is not + listed in \l {sources.fileextensions-variable}{sources.fileextensions}; + for example, \c .qdocinc. + The command can have either one or two arguments. The first argument is always a file name. The contents of the file must be @@ -3809,7 +3812,7 @@ QDoc renders this page \l{corefeatures.html} {as shown here}. - \target 2-argument-form} + \target 2-argument-form \section2 \\include filename snippet-identifier It is a waste of time to make a separate \c .qdocinc file for every @@ -3841,8 +3844,12 @@ It works as expected. The sequence of QDoc commands and text found between the two tags with the same name as the second argument is - sent to the QDoc input stream. You can even nest these snippets, - although it's not clear why you would want to do that. + sent to the QDoc input stream. You can even have nested snippets. + + \note Snippet identifiers work also within documentation comment + (\beginqdoc .. \endqdoc) blocks, so it's not necessary to use a + separate \c .qdocinc file. When processing a comment block, QDoc + removes any \c {//!} comment lines from the generated output. \target meta-command \section1 \\meta @@ -3865,7 +3872,6 @@ \meta {technology} {User Interface} \meta {platform} {OS X 10.6} - \meta {platform} {Symbian} \meta {platform} {MeeGo} \meta {audience} {user} \meta {audience} {programmer} @@ -3905,7 +3911,6 @@ <component>QtGui</component> </prodinfo> <othermeta name="platform" content="MeeGo"/> - <othermeta name="platform" content="Symbian"/> <othermeta name="platform" content="OS X 10.6"/> <othermeta name="technology" content="User Interface"/> </metadata> diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp index 2c8d0edb4..f64f88300 100644 --- a/src/qdoc/generator.cpp +++ b/src/qdoc/generator.cpp @@ -190,6 +190,41 @@ void Generator::appendFullNames(Text& text, const NodeList& nodes, const Node* r } } +/*! + Append the signature for the function named in \a node to + \a text, so that is is a link to the documentation for that + function. + */ +void Generator::appendSignature(Text& text, const Node* node) +{ + text << Atom(Atom::LinkNode, CodeMarker::stringForNode(node)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, node->signature(false, true)) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); +} + +/*! + Generate a bullet list of function signatures. The function + nodes are in \a nodes. It uses the \a relative node and the + \a marker for the generation. + */ +void Generator::signatureList(const NodeList& nodes, const Node* relative, CodeMarker* marker) +{ + Text text; + int count = 0; + text << Atom(Atom::ListLeft, QString("bullet")); + NodeList::ConstIterator n = nodes.constBegin(); + while (n != nodes.constEnd()) { + text << Atom(Atom::ListItemNumber, QString::number(++count)); + text << Atom(Atom::ListItemLeft, QString("bullet")); + appendSignature(text, *n); + text << Atom(Atom::ListItemRight, QString("bullet")); + ++n; + } + text << Atom(Atom::ListRight, QString("bullet")); + generateText(text, relative, marker); +} + int Generator::appendSortedNames(Text& text, const ClassNode* cn, const QList<RelatedClass>& rc) { QList<RelatedClass>::ConstIterator r; @@ -564,7 +599,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) { const FunctionNode *fn = static_cast<const FunctionNode *>(node); - if (fn->metaness() == FunctionNode::Dtor) + if (fn->isDtor()) anchorRef = "#dtor." + fn->name().mid(1); else if (fn->hasOneAssociatedProperty() && fn->doc().isEmpty()) @@ -752,7 +787,63 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) } } if (node->doc().isEmpty()) { - if (!node->isWrapper() && !quiet && !node->isReimplemented()) { // ### might be unnecessary + /* + Test for special function, like a destructor or copy constructor, + that has no documentation. + */ + if (node->type() == Node::Function) { + const FunctionNode* func = static_cast<const FunctionNode*>(node); + if (func->isDtor()) { + Text text; + text << "Destroys the instance of "; + text << func->parent()->name() << "."; + if (func->isVirtual()) + text << " The destructor is virtual."; + out() << "<p>"; + generateText(text, node, marker); + out() << "</p>"; + } + else if (func->isCtor()) { + Text text; + text << "Default constructs an instance of "; + text << func->parent()->name() << "."; + out() << "<p>"; + generateText(text, node, marker); + out() << "</p>"; + } + else if (func->isCCtor()) { + Text text; + text << "Copy constructor."; + out() << "<p>"; + generateText(text, node, marker); + out() << "</p>"; + } + else if (func->isMCtor()) { + Text text; + text << "Move-copy constructor."; + out() << "<p>"; + generateText(text, node, marker); + out() << "</p>"; + } + else if (func->isCAssign()) { + Text text; + text << "Copy-assignment operator."; + out() << "<p>"; + generateText(text, node, marker); + out() << "</p>"; + } + else if (func->isMAssign()) { + Text text; + text << "Move-assignment operator."; + out() << "<p>"; + generateText(text, node, marker); + out() << "</p>"; + } + else if (!node->isWrapper() && !quiet && !node->isReimplemented()) { + node->location().warning(tr("No documentation for '%1'").arg(node->plainSignature())); + } + } + else if (!node->isWrapper() && !quiet && !node->isReimplemented()) { node->location().warning(tr("No documentation for '%1'").arg(node->plainSignature())); } } @@ -1333,24 +1424,83 @@ bool Generator::generateText(const Text& text, return result; } +/* + The node is an aggregate, typically a class node, which has + a threadsafeness level. This function checks all the children + of the node to see if they are exceptions to the node's + threadsafeness. If there are any exceptions, the exceptions + are added to the appropriate set (reentrant, threadsafe, and + nonreentrant, and true is returned. If there are no exceptions, + the three node lists remain empty and false is returned. + */ +static bool hasExceptions(const Node* node, + NodeList& reentrant, + NodeList& threadsafe, + NodeList& nonreentrant) +{ + bool result = false; + Node::ThreadSafeness ts = node->threadSafeness(); + const Aggregate* a = static_cast<const Aggregate*>(node); + NodeList::ConstIterator c = a->childNodes().constBegin(); + while (c != a->childNodes().constEnd()) { + if (!(*c)->isObsolete()){ + switch ((*c)->threadSafeness()) { + case Node::Reentrant: + reentrant.append(*c); + if (ts == Node::ThreadSafe) + result = true; + break; + case Node::ThreadSafe: + threadsafe.append(*c); + if (ts == Node::Reentrant) + result = true; + break; + case Node::NonReentrant: + nonreentrant.append(*c); + result = true; + break; + default: + break; + } + } + ++c; + } + return result; +} + +static void startNote(Text& text) +{ + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "Note:" + << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) + << " "; +} + +/*! + Generates text that explains how threadsafe and/or reentrant + \a node is. + */ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker) { - Text text; - Node::ThreadSafeness threadSafeness = node->threadSafeness(); + Text text, rlink, tlink; + NodeList reentrant; + NodeList threadsafe; + NodeList nonreentrant; + Node::ThreadSafeness ts = node->threadSafeness(); + bool exceptions = false; - Text rlink; rlink << Atom(Atom::Link,"reentrant") << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << "reentrant" << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - Text tlink; tlink << Atom(Atom::Link,"thread-safe") << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << "thread-safe" << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - switch (threadSafeness) { + switch (ts) { case Node::UnspecifiedSafeness: break; case Node::NonReentrant: @@ -1367,110 +1517,76 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker) break; case Node::Reentrant: case Node::ThreadSafe: - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) - << "Note:" - << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD) - << " "; - + startNote(text); if (node->isAggregate()) { - const Aggregate* innerNode = static_cast<const Aggregate*>(node); - text << "All functions in this " - << typeString(node) - << " are "; - if (threadSafeness == Node::ThreadSafe) + exceptions = hasExceptions(node, reentrant, threadsafe, nonreentrant); + text << "All functions in this " << typeString(node) << " are "; + if (ts == Node::ThreadSafe) text << tlink; else text << rlink; - bool exceptions = false; - NodeList reentrant; - NodeList threadsafe; - NodeList nonreentrant; - NodeList::ConstIterator c = innerNode->childNodes().constBegin(); - while (c != innerNode->childNodes().constEnd()) { - - if ((*c)->status() != Node::Obsolete){ - switch ((*c)->threadSafeness()) { - case Node::Reentrant: - reentrant.append(*c); - if (threadSafeness == Node::ThreadSafe) - exceptions = true; - break; - case Node::ThreadSafe: - threadsafe.append(*c); - if (threadSafeness == Node::Reentrant) - exceptions = true; - break; - case Node::NonReentrant: - nonreentrant.append(*c); - exceptions = true; - break; - default: - break; - } - } - ++c; - } - if (!exceptions) + if (!exceptions || (ts == Node::Reentrant && !threadsafe.isEmpty())) text << "."; - else if (threadSafeness == Node::Reentrant) { - if (nonreentrant.isEmpty()) { - if (!threadsafe.isEmpty()) { - text << ", but "; - appendFullNames(text,threadsafe,innerNode); - singularPlural(text,threadsafe); - text << " also " << tlink << "."; - } - else - text << "."; - } - else { - text << ", except for "; - appendFullNames(text,nonreentrant,innerNode); - text << ", which"; - singularPlural(text,nonreentrant); - text << " nonreentrant."; - if (!threadsafe.isEmpty()) { - text << " "; - appendFullNames(text,threadsafe,innerNode); - singularPlural(text,threadsafe); - text << " " << tlink << "."; - } - } - } - else { // thread-safe - if (!nonreentrant.isEmpty() || !reentrant.isEmpty()) { - text << ", except for "; - if (!reentrant.isEmpty()) { - appendFullNames(text,reentrant,innerNode); - text << ", which"; - singularPlural(text,reentrant); - text << " only " << rlink; - if (!nonreentrant.isEmpty()) - text << ", and "; - } - if (!nonreentrant.isEmpty()) { - appendFullNames(text,nonreentrant,innerNode); - text << ", which"; - singularPlural(text,nonreentrant); - text << " nonreentrant."; - } - text << "."; - } - } + else + text << " with the following exceptions:"; } else { text << "This " << typeString(node) << " is "; - if (threadSafeness == Node::ThreadSafe) + if (ts == Node::ThreadSafe) text << tlink; else text << rlink; - text << "."; } text << Atom::ParaRight; + break; + default: + break; } generateText(text,node,marker); + + if (exceptions) { + text.clear(); + if (ts == Node::Reentrant) { + if (!nonreentrant.isEmpty()) { + startNote(text); + text << "These functions are not " + << rlink + << ":" + << Atom::ParaRight; + signatureList(nonreentrant, node, marker); + } + if (!threadsafe.isEmpty()) { + text.clear(); + startNote(text); + text << "These functions are also " + << tlink + << ":" + << Atom::ParaRight; + generateText(text, node, marker); + signatureList(threadsafe, node, marker); + } + } + else { // thread-safe + if (!reentrant.isEmpty()) { + startNote(text); + text << "These functions are only " + << rlink + << ":" + << Atom::ParaRight; + signatureList(reentrant, node, marker); + } + if (!nonreentrant.isEmpty()) { + text.clear(); + startNote(text); + text << "These functions are not " + << rlink + << ":" + << Atom::ParaRight; + signatureList(nonreentrant, node, marker); + } + } + } } /*! @@ -1481,7 +1597,7 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker) if (node->type() != Node::Function) return; const FunctionNode *func = static_cast<const FunctionNode *>(node); - if (func->metaness() != FunctionNode::Signal) + if (!func->isSignal()) return; if (node->parent()->overloads(node->name()).count() <= 1) return; diff --git a/src/qdoc/generator.h b/src/qdoc/generator.h index c0adc1468..5b301f9f1 100644 --- a/src/qdoc/generator.h +++ b/src/qdoc/generator.h @@ -200,6 +200,8 @@ protected: const Node *actualNode); void appendFullNames(Text& text, const NodeList& nodes, const Node* relative); int appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes); + void appendSignature(Text& text, const Node* node); + void signatureList(const NodeList& nodes, const Node* relative, CodeMarker* marker); private: static Generator* currentGenerator_; diff --git a/src/qdoc/helpprojectwriter.cpp b/src/qdoc/helpprojectwriter.cpp index 1689c0575..96524100f 100644 --- a/src/qdoc/helpprojectwriter.cpp +++ b/src/qdoc/helpprojectwriter.cpp @@ -381,7 +381,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, // Only insert keywords for non-constructors. Constructors are covered // by the classes themselves. - if (funcNode->metaness() != FunctionNode::Ctor) + if (!funcNode->isSomeCtor()) project.keywords.append(keywordDetails(node)); // Insert member status flags into the entries for the parent @@ -479,7 +479,7 @@ void HelpProjectWriter::generateSections(HelpProject &project, const Aggregate *inner = static_cast<const Aggregate *>(node); // Ensure that we don't visit nodes more than once. - QMap<QString, const Node*> childMap; + QSet<const Node*> childSet; foreach (const Node *childNode, inner->childNodes()) { if (childNode->isIndexNode()) continue; @@ -488,7 +488,7 @@ void HelpProjectWriter::generateSections(HelpProject &project, continue; if (childNode->type() == Node::Document) { - childMap[static_cast<const DocumentNode *>(childNode)->fullTitle()] = childNode; + childSet << childNode; } else if (childNode->isQmlPropertyGroup() || childNode->isJsPropertyGroup()) { /* @@ -504,7 +504,7 @@ void HelpProjectWriter::generateSections(HelpProject &project, foreach (const Node* n, inner->childNodes()) { if (n->access() == Node::Private) continue; - childMap[n->fullDocumentName()] = n; + childSet << n; } } else { @@ -519,10 +519,10 @@ void HelpProjectWriter::generateSections(HelpProject &project, if (funcNode->isOverload()) continue; } - childMap[childNode->fullDocumentName()] = childNode; + childSet << childNode; } } - foreach (const Node *child, childMap) + foreach (const Node *child, childSet) generateSections(project, writer, child); } } diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp index d72869835..45fee6166 100644 --- a/src/qdoc/htmlgenerator.cpp +++ b/src/qdoc/htmlgenerator.cpp @@ -1383,7 +1383,6 @@ void HtmlGenerator::generateClassLikeNode(Aggregate* inner, CodeMarker* marker) generateBrief(inner, marker); generateRequisites(inner, marker); generateStatus(inner, marker); - generateThreadSafeness(inner, marker); out() << "<ul>\n"; @@ -1408,6 +1407,7 @@ void HtmlGenerator::generateClassLikeNode(Aggregate* inner, CodeMarker* marker) << "Compatibility members</a></li>\n"; out() << "</ul>\n"; + generateThreadSafeness(inner, marker); bool needOtherSection = false; @@ -1498,9 +1498,7 @@ void HtmlGenerator::generateClassLikeNode(Aggregate* inner, CodeMarker* marker) names << (*m)->name(); if ((*m)->type() == Node::Function) { const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m); - if (func->metaness() == FunctionNode::Ctor || - func->metaness() == FunctionNode::Dtor || - func->overloadNumber() != 0) + if (func->isSomeCtor() || func->isDtor() || func->overloadNumber() != 0) names.clear(); } else if ((*m)->type() == Node::Property) { @@ -1630,7 +1628,7 @@ void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker = CodeMarker::markerForLanguage(QLatin1String("QML")); generateHeader(htmlTitle, qbtn, marker); - QList<Section> sections = marker->sections(qbtn, CodeMarker::Summary, CodeMarker::Okay); + QList<Section> sections = marker->qmlSections(qbtn, CodeMarker::Summary); generateTableOfContents(qbtn,marker,§ions); generateKeywordAnchors(qbtn); generateTitle(htmlTitle, @@ -1638,6 +1636,17 @@ void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* subTitleSize, qbtn, marker); + + s = sections.constBegin(); + while (s != sections.constEnd()) { + QString ref = registerRef((*s).name.toLower()); + out() << "<a name=\"" << ref + << "\"></a>" << divNavTop << '\n'; + out() << "<h2 id=\"" << ref << "\">" << protectEnc((*s).name) << "</h2>\n"; + generateQmlSummary(*s, qbtn, marker); + ++s; + } + generateExtractionMark(qbtn, DetailedDescriptionMark); out() << "<div class=\"descr\"> <a name=\"" << registerRef("details") << "\"></a>\n"; // QTBUG-9504 @@ -1645,6 +1654,19 @@ void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* out() << "</div>\n"; // QTBUG-9504 generateAlsoList(qbtn, marker); generateExtractionMark(qbtn, EndMark); + + sections = marker->qmlSections(qbtn, CodeMarker::Detailed); + s = sections.constBegin(); + while (s != sections.constEnd()) { + out() << "<h2>" << protectEnc((*s).name) << "</h2>\n"; + NodeList::ConstIterator m = (*s).members.constBegin(); + while (m != (*s).members.constEnd()) { + generateDetailedQmlMember(*m, qbtn, marker); + out() << "<br/>\n"; + ++m; + } + ++s; + } generateFooter(qbtn); } @@ -1994,10 +2016,12 @@ void HtmlGenerator::generateHeader(const QString& title, out() << " <title>" << protectEnc(title) << divider - << titleSuffix - << QLatin1Char(' ') - << shortVersion - << "</title>\n"; + << titleSuffix; + + if (!shortVersion.isEmpty()) + out() << QLatin1Char(' ') << shortVersion; + + out() << "</title>\n"; // Include style sheet and script links. out() << headerStyles; @@ -3215,7 +3239,7 @@ void HtmlGenerator::generateList(const Node* relative, CodeMarker* marker, const comment where the topic is \group, \module, \qmlmodule, or \jsmodule */ - if (!relative || !relative->isCollectionNode()) { + if (relative && !relative->isCollectionNode()) { relative->doc().location().warning(tr("\\generatelist {%1} is only allowed in \\group, " "\\module, \\qmlmodule, and \\jsmodule comments.").arg(selector)); return; diff --git a/src/qdoc/jscodemarker.cpp b/src/qdoc/jscodemarker.cpp index 669040da0..496eb8c30 100644 --- a/src/qdoc/jscodemarker.cpp +++ b/src/qdoc/jscodemarker.cpp @@ -44,10 +44,12 @@ #include "tree.h" #include "generator.h" +#ifndef QT_NO_DECLARATIVE #include <private/qqmljsast_p.h> #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> +#endif QT_BEGIN_NAMESPACE @@ -64,6 +66,7 @@ JsCodeMarker::~JsCodeMarker() */ bool JsCodeMarker::recognizeCode(const QString &code) { +#ifndef QT_NO_DECLARATIVE QQmlJS::Engine engine; QQmlJS::Lexer lexer(&engine); QQmlJS::Parser parser(&engine); @@ -73,6 +76,9 @@ bool JsCodeMarker::recognizeCode(const QString &code) lexer.setCode(newCode, 1); return parser.parseProgram(); +#else + return false; +#endif } /*! @@ -112,6 +118,7 @@ QString JsCodeMarker::addMarkUp(const QString &code, const Node * /* relative */, const Location &location) { +#ifndef QT_NO_DECLARATIVE QQmlJS::Engine engine; QQmlJS::Lexer lexer(&engine); @@ -137,6 +144,10 @@ QString JsCodeMarker::addMarkUp(const QString &code, output = protect(code); } return output; +#else + location.warning("QtDeclarative not installed; cannot parse QML or JS."); + return QString(); +#endif } QT_END_NAMESPACE diff --git a/src/qdoc/main.cpp b/src/qdoc/main.cpp index 4c4354773..500a085cc 100644 --- a/src/qdoc/main.cpp +++ b/src/qdoc/main.cpp @@ -728,8 +728,11 @@ int main(int argc, char **argv) Generator::setQDocPass(Generator::Prepare); if (parser.isSet(generateOption)) Generator::setQDocPass(Generator::Generate); - if (parser.isSet(singleExecOption)) + if (parser.isSet(singleExecOption)) { Generator::setSingleExec(); + if (parser.isSet(indexDirOption)) + qDebug() << "WARNING: -indexdir option ignored: Index files are not used in -single-exec mode."; + } if (parser.isSet(writeQaPagesOption)) Generator::setWriteQaPages(); if (parser.isSet(logProgressOption)) @@ -788,13 +791,13 @@ int main(int argc, char **argv) translators.clear(); #endif QmlTypeNode::terminate(); - //#define DEBUG_SHUTDOWN_CRASH + #ifdef DEBUG_SHUTDOWN_CRASH - Generator::startDebugging("main(): Delete qdoc database"); + qDebug() << "main(): Delete qdoc database"; #endif QDocDatabase::destroyQdocDB(); #ifdef DEBUG_SHUTDOWN_CRASH - Generator::stopDebugging("main(): qdoc database deleted"); + qDebug() << "main(): qdoc database deleted"; #endif return EXIT_SUCCESS; diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp index 93f9312f7..4fa565285 100644 --- a/src/qdoc/node.cpp +++ b/src/qdoc/node.cpp @@ -861,7 +861,7 @@ Node* Aggregate::findChildNode(const QString& name, NodeType type) } /*! - Find a function node that is a child of this node, such + Find a function node that is a child of this nose, such that the function node has the specified \a name. */ FunctionNode *Aggregate::findFunctionNode(const QString& name, const QString& params) const @@ -930,58 +930,21 @@ FunctionNode *Aggregate::findFunctionNode(const QString& name, const QString& pa /*! Find the function node that is a child of this node, such that the function has the same name and signature as the - function described in \a f1. + \a clone node. */ -FunctionNode *Aggregate::findFunctionNode(const Declaration& f1) const +FunctionNode *Aggregate::findFunctionNode(const FunctionNode *clone) const { - QMap<QString,Node*>::ConstIterator c = primaryFunctionMap_.constFind(f1.name_); + QMap<QString,Node*>::ConstIterator c = primaryFunctionMap_.constFind(clone->name()); if (c != primaryFunctionMap_.constEnd()) { - FunctionNode* f2 = (FunctionNode*) *c; - if (f1.isConst_ == f2->isConst()) { - if (isSameSignature(f1.pvect_, f2)) { - return f2; - } - } - if (secondaryFunctionMap_.contains(f1.name_)) { - const NodeList& secs = secondaryFunctionMap_[f1.name_]; - NodeList::ConstIterator s = secs.constBegin(); - while (s != secs.constEnd()) { - f2 = (FunctionNode*) *s; - if (f1.isConst_ == f2->isConst()) { - if (isSameSignature(f1.pvect_, f2)) - return f2; - } - ++s; - } - } - } - return 0; -} - -/*! - Find the function node that is a child of this node, such - that the function has the same name and signature as the - function node \a f1. - */ -FunctionNode *Aggregate::findFunctionNode(const FunctionNode* f1) const -{ - QMap<QString,Node*>::ConstIterator c = primaryFunctionMap_.constFind(f1->name()); - if (c != primaryFunctionMap_.constEnd()) { - FunctionNode* f2 = (FunctionNode*) *c; - if (f1->isConst() == f2->isConst()) { - if (isSameSignature(f1->parameters(), f2)) { - return f2; - } + if (isSameSignature(clone, (FunctionNode *) *c)) { + return (FunctionNode *) *c; } - if (secondaryFunctionMap_.contains(f1->name())) { - const NodeList& secs = secondaryFunctionMap_[f1->name()]; + else if (secondaryFunctionMap_.contains(clone->name())) { + const NodeList& secs = secondaryFunctionMap_[clone->name()]; NodeList::ConstIterator s = secs.constBegin(); while (s != secs.constEnd()) { - f2 = (FunctionNode*) *s; - if (f1->isConst() == f2->isConst()) { - if (isSameSignature(f1->parameters(), f2)) - return f2; - } + if (isSameSignature(clone, (FunctionNode *) *s)) + return (FunctionNode *) *s; ++s; } } @@ -1225,19 +1188,18 @@ void Aggregate::setIncludes(const QStringList& includes) } /*! - Compare the function signature contained parameter vector - \a pv1 with the signature of the function node \a f2, and - return \c true if they are the same. + f1 is always the clone */ -bool Aggregate::isSameSignature(const QVector<Parameter>& pv1, const FunctionNode* f2) +bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2) { - const QVector<Parameter>& pv2 = f2->parameters(); - if (pv1.size() != pv2.size()) + if (f1->parameters().size() != f2->parameters().size()) + return false; + if (f1->isConst() != f2->isConst()) return false; - QVector<Parameter>::ConstIterator p1 = pv1.constBegin(); - QVector<Parameter>::ConstIterator p2 = pv2.constBegin(); - while (p2 != pv2.constEnd()) { + QVector<Parameter>::ConstIterator p1 = f1->parameters().constBegin(); + QVector<Parameter>::ConstIterator p2 = f2->parameters().constBegin(); + while (p2 != f2->parameters().constEnd()) { if ((*p1).hasType() && (*p2).hasType()) { if ((*p1).rightType() != (*p2).rightType()) return false; @@ -1301,6 +1263,8 @@ void Aggregate::addChild(Node *child) if (child->parent() == 0) { child->setParent(this); child->setOutputSubdirectory(this->outputSubdirectory()); + child->setUrl(QString()); + child->setIndexNodeFlag(isIndexNode()); } } @@ -1999,7 +1963,6 @@ QString Parameter::reconstruct(bool value) const return p; } - /*! \class FunctionNode */ @@ -2021,6 +1984,9 @@ FunctionNode::FunctionNode(Aggregate *parent, const QString& name) attached_(false), privateSignal_(false), overload_(false), + isDeleted_(false), + isDefaulted_(false), + isFinal_(false), reimplementedFrom_(0) { setGenus(Node::CPP); @@ -2044,6 +2010,9 @@ FunctionNode::FunctionNode(NodeType type, Aggregate *parent, const QString& name attached_(attached), privateSignal_(false), overload_(false), + isDeleted_(false), + isDefaulted_(false), + isFinal_(false), reimplementedFrom_(0) { setGenus(Node::QML); @@ -2056,15 +2025,78 @@ FunctionNode::FunctionNode(NodeType type, Aggregate *parent, const QString& name } /*! - Sets the \a virtualness of this function. If the \a virtualness - is PureVirtual, and if the parent() is a ClassNode, set the parent's - \e abstract flag to true. + Returns this function's virtualness value as a string + for use as an attribute value in index files. */ -void FunctionNode::setVirtualness(Virtualness v) +QString FunctionNode::virtualness() const { - virtualness_ = v; - if ((v == PureVirtual) && parent() && (parent()->type() == Node::Class)) - parent()->setAbstract(true); + switch (virtualness_) { + case FunctionNode::NormalVirtual: + return "virtual"; + case FunctionNode::PureVirtual: + return "pure"; + case FunctionNode::NonVirtual: + default: + break; + } + return "non"; +} + +/*! + Sets the function node's virtualness value based on the value + of string \a t, which is the value of the function's \e{virtual} + attribute in an index file. If \a t is \e{pure}, and if the + parent() is a C++ class, set the parent's \e abstract flag to + \c {true}. + */ +void FunctionNode::setVirtualness(const QString& t) +{ + if (t == QLatin1String("non")) + virtualness_ = NonVirtual; + else if (t == QLatin1String("virtual")) + virtualness_ = NormalVirtual; + else if (t == QLatin1String("pure")) { + virtualness_ = PureVirtual; + if (parent() && parent()->isClass()) + parent()->setAbstract(true); + } +} + +/*! + Sets the function node's Metaness value based on the value + of string \a t, which is the value of the function's "meta" + attribute in an index file. + */ +void FunctionNode::setMetaness(const QString& t) +{ + if (t == QLatin1String("plain")) + metaness_ = Plain; + else if (t == QLatin1String("signal")) + metaness_ = Signal; + else if (t == QLatin1String("slot")) + metaness_ = Slot; + else if (t == QLatin1String("constructor")) + metaness_ = Ctor; + else if (t == QLatin1String("copy-constructor")) + metaness_ = CCtor; + else if (t == QLatin1String("move-constructor")) + metaness_ = MCtor; + else if (t == QLatin1String("destructor")) + metaness_ = Dtor; + else if (t == QLatin1String("macro")) + metaness_ = MacroWithParams; + else if (t == QLatin1String("macrowithparams")) + metaness_ = MacroWithParams; + else if (t == QLatin1String("macrowithoutparams")) + metaness_ = MacroWithoutParams; + else if (t == QLatin1String("copy-assign")) + metaness_ = CAssign; + else if (t == QLatin1String("move-assign")) + metaness_ = MAssign; + else if (t == QLatin1String("native")) + metaness_ = Native; + else + metaness_ = Plain; } /*! \fn void FunctionNode::setOverloadFlag(bool b) @@ -2090,6 +2122,43 @@ void FunctionNode::setReimplemented(bool b) } /*! + Returns a string representing the Metaness enum value for + this function. It is used in index files. + */ +QString FunctionNode::metaness() const +{ + switch (metaness_) { + case FunctionNode::Plain: + return "plain"; + case FunctionNode::Signal: + return "signal"; + case FunctionNode::Slot: + return "slot"; + case FunctionNode::Ctor: + return "constructor"; + case FunctionNode::CCtor: + return "copy-constructor"; + case FunctionNode::MCtor: + return "move-constructor"; + case FunctionNode::Dtor: + return "destructor"; + case FunctionNode::MacroWithParams: + return "macrowithparams"; + case FunctionNode::MacroWithoutParams: + return "macrowithoutparams"; + case FunctionNode::Native: + return "native"; + case FunctionNode::CAssign: + return "copy-assign"; + case FunctionNode::MAssign: + return "move-assign"; + default: + return "plain"; + } + return QString(); +} + +/*! Append \a parameter to the parameter list. */ void FunctionNode::addParameter(const Parameter& parameter) @@ -2099,11 +2168,11 @@ void FunctionNode::addParameter(const Parameter& parameter) /*! */ -void FunctionNode::borrowParameterNames(const Declaration& declData) +void FunctionNode::borrowParameterNames(const FunctionNode *source) { QVector<Parameter>::Iterator t = parameters_.begin(); - QVector<Parameter>::ConstIterator s = declData.pvect_.constBegin(); - while (s != declData.pvect_.constEnd() && t != parameters_.end()) { + QVector<Parameter>::ConstIterator s = source->parameters_.constBegin(); + while (s != source->parameters_.constEnd() && t != parameters_.end()) { if (!(*s).name().isEmpty()) (*t).setName((*s).name()); ++s; diff --git a/src/qdoc/node.h b/src/qdoc/node.h index cc2c784fa..870a55cdf 100644 --- a/src/qdoc/node.h +++ b/src/qdoc/node.h @@ -53,7 +53,6 @@ class ExampleNode; class TypedefNode; class QmlTypeNode; class QDocDatabase; -class Declaration; class FunctionNode; class PropertyNode; class CollectionNode; @@ -189,7 +188,7 @@ public: void setPageType(PageType t) { pageType_ = (unsigned char) t; } void setPageType(const QString& t); void setParent(Aggregate* n) { parent_ = n; } - void setIndexNodeFlag() { indexNodeFlag_ = true; } + void setIndexNodeFlag(bool isIndexNode = true) { indexNodeFlag_ = isIndexNode; } virtual void setOutputFileName(const QString& ) { } bool isQmlNode() const { return genus() == QML; } @@ -208,6 +207,7 @@ public: virtual bool isQmlBasicType() const { return false; } virtual bool isJsBasicType() const { return false; } virtual bool isEnumType() const { return false; } + virtual bool isTypedef() const { return false; } virtual bool isExample() const { return false; } virtual bool isExampleFile() const { return false; } virtual bool isHeaderFile() const { return false; } @@ -373,37 +373,6 @@ private: }; Q_DECLARE_TYPEINFO(Node::DocSubtype, Q_PRIMITIVE_TYPE); -class Parameter -{ -public: - Parameter() {} - Parameter(const QString& dataType, - const QString& rightType = QString(), - const QString& name = QString(), - const QString& defaultValue = QString()); - Parameter(const Parameter& p); - - Parameter& operator=(const Parameter& p); - - void setName(const QString& name) { name_ = name; } - - bool hasType() const { return dataType_.length() + rightType_.length() > 0; } - const QString& dataType() const { return dataType_; } - const QString& rightType() const { return rightType_; } - const QString& name() const { return name_; } - const QString& defaultValue() const { return defaultValue_; } - - QString reconstruct(bool value = false) const; - - public: - QString dataType_; - QString rightType_; // mws says remove this 04/08/2015 - QString name_; - QString defaultValue_; -}; -//friend class QTypeInfo<Parameter>; -//Q_DECLARE_TYPEINFO(Parameter, Q_MOVABLE_TYPE); - class Aggregate : public Node { public: @@ -413,8 +382,7 @@ public: Node* findChildNode(const QString& name, NodeType type); virtual void findChildren(const QString& name, NodeList& nodes) const Q_DECL_OVERRIDE; FunctionNode* findFunctionNode(const QString& name, const QString& params) const; - FunctionNode* findFunctionNode(const Declaration& declData) const; - FunctionNode* findFunctionNode(const FunctionNode* f1) const; + FunctionNode* findFunctionNode(const FunctionNode* clone) const; void addInclude(const QString &include); void setIncludes(const QStringList &includes); void normalizeOverloads(); @@ -440,6 +408,7 @@ public: virtual QString outputFileName() const Q_DECL_OVERRIDE { return outputFileName_; } virtual QmlPropertyNode* hasQmlProperty(const QString& ) const Q_DECL_OVERRIDE; virtual QmlPropertyNode* hasQmlProperty(const QString&, bool attached) const Q_DECL_OVERRIDE; + virtual QmlTypeNode* qmlBaseNode() { return 0; } void addChild(Node* child, const QString& title); const QStringList& groupNames() const { return groupNames_; } virtual void appendGroupName(const QString& t) Q_DECL_OVERRIDE { groupNames_.append(t); } @@ -456,7 +425,7 @@ protected: private: friend class Node; - static bool isSameSignature(const QVector<Parameter>& pv1, const FunctionNode* f2); + static bool isSameSignature(const FunctionNode* f1, const FunctionNode* f2); void removeRelated(Node* pseudoChild); void addRelated(Node* pseudoChild); @@ -680,7 +649,7 @@ public: const QString& qmlBaseName() const { return qmlBaseName_; } void setQmlBaseName(const QString& name) { qmlBaseName_ = name; } bool qmlBaseNodeNotSet() const { return (qmlBaseNode_ == 0); } - QmlTypeNode* qmlBaseNode(); + virtual QmlTypeNode* qmlBaseNode() Q_DECL_OVERRIDE; void setQmlBaseNode(QmlTypeNode* b) { qmlBaseNode_ = b; } void requireCppClass() { cnodeRequired_ = true; } bool cppClassRequired() const { return cnodeRequired_; } @@ -837,6 +806,7 @@ public: TypedefNode(Aggregate* parent, const QString& name); virtual ~TypedefNode() { } + virtual bool isTypedef() const { return true; } const EnumNode* associatedEnum() const { return associatedEnum_; } private: @@ -853,19 +823,57 @@ inline void EnumNode::setFlagsType(TypedefNode* t) t->setAssociatedEnum(this); } +class Parameter +{ +public: + Parameter() {} + Parameter(const QString& dataType, + const QString& rightType = QString(), + const QString& name = QString(), + const QString& defaultValue = QString()); + Parameter(const Parameter& p); + + Parameter& operator=(const Parameter& p); + + void setName(const QString& name) { name_ = name; } + + bool hasType() const { return dataType_.length() + rightType_.length() > 0; } + const QString& dataType() const { return dataType_; } + const QString& rightType() const { return rightType_; } + const QString& name() const { return name_; } + const QString& defaultValue() const { return defaultValue_; } + + QString reconstruct(bool value = false) const; + + public: + QString dataType_; + QString rightType_; // mws says remove this 04/08/2015 + QString name_; + QString defaultValue_; +}; + +//friend class QTypeInfo<Parameter>; +//Q_DECLARE_TYPEINFO(Parameter, Q_MOVABLE_TYPE); + class FunctionNode : public LeafNode { public: + enum Virtualness { NonVirtual, NormalVirtual, PureVirtual }; + enum Metaness { Plain, Signal, Slot, Ctor, Dtor, + CCtor, // copy constructor + MCtor, // move-copy constructor MacroWithParams, MacroWithoutParams, - Native }; - enum Virtualness { NonVirtual, NormalVirtual, PureVirtual }; + Native, + CAssign, // copy-assignment operator + MAssign // move-assignment operator + }; FunctionNode(Aggregate* parent, const QString &name); FunctionNode(NodeType type, Aggregate* parent, const QString &name, bool attached); @@ -874,7 +882,10 @@ public: void setReturnType(const QString& t) { returnType_ = t; } void setParentPath(const QStringList& p) { parentPath_ = p; } void setMetaness(Metaness t) { metaness_ = t; } - void setVirtualness(Virtualness v); + void setMetaness(const QString& t); + void setVirtualness(const QString& t); + void setVirtualness(Virtualness v) { virtualness_ = v; } + void setVirtual() { virtualness_ = NormalVirtual; } void setConst(bool b) { const_ = b; } void setStatic(bool b) { static_ = b; } unsigned char overloadNumber() const { return overloadNumber_; } @@ -883,20 +894,32 @@ public: void setReimplemented(bool b); void addParameter(const Parameter& parameter); inline void setParameters(const QVector<Parameter>& parameters); - void borrowParameterNames(const Declaration& declData); + void borrowParameterNames(const FunctionNode* source); void setReimplementedFrom(FunctionNode* from); const QString& returnType() const { return returnType_; } - Metaness metaness() const { return metaness_; } - bool isMacro() const { - return metaness_ == MacroWithParams || metaness_ == MacroWithoutParams; - } - Virtualness virtualness() const { return virtualness_; } + QString metaness() const; + QString virtualness() const; bool isConst() const { return const_; } bool isStatic() const { return static_; } bool isOverload() const { return overload_; } bool isReimplemented() const Q_DECL_OVERRIDE { return reimplemented_; } bool isFunction() const Q_DECL_OVERRIDE { return true; } + bool isSomeCtor() const { return isCtor() || isCCtor() || isMCtor(); } + bool isMacroWithParams() const { return (metaness_ == MacroWithParams); } + bool isMacroWithoutParams() const { return (metaness_ == MacroWithoutParams); } + bool isMacro() const { return (isMacroWithParams() || isMacroWithoutParams()); } + bool isSignal() const { return (metaness_ == Signal); } + bool isSlot() const { return (metaness_ == Slot); } + bool isCtor() const { return (metaness_ == Ctor); } + bool isDtor() const { return (metaness_ == Dtor); } + bool isCCtor() const { return (metaness_ == CCtor); } + bool isMCtor() const { return (metaness_ == MCtor); } + bool isCAssign() const { return (metaness_ == CAssign); } + bool isMAssign() const { return (metaness_ == MAssign); } + bool isNonvirtual() const { return (virtualness_ == NonVirtual); } + bool isVirtual() const { return (virtualness_ == NormalVirtual); } + bool isPureVirtual() const { return (virtualness_ == PureVirtual); } virtual bool isQmlSignal() const Q_DECL_OVERRIDE { return (type() == Node::QmlSignal) && (genus() == Node::QML); } @@ -929,7 +952,7 @@ public: bool hasActiveAssociatedProperty() const; QStringList reconstructParameters(bool values = false) const; - virtual QString signature(bool values, bool noReturnType = false) const; + virtual QString signature(bool values, bool noReturnType = false) const Q_DECL_OVERRIDE; virtual QString element() const Q_DECL_OVERRIDE { return parent()->name(); } virtual bool isAttached() const Q_DECL_OVERRIDE { return attached_; } virtual bool isQtQuickNode() const Q_DECL_OVERRIDE { return parent()->isQtQuickNode(); } @@ -948,6 +971,15 @@ public: void debug() const; + bool isDeleted() const { return isDeleted_; } + void setIsDeleted(bool b) { isDeleted_ = b; } + + bool isDefaulted() const { return isDefaulted_; } + void setIsDefaulted(bool b) { isDefaulted_ = b; } + + void setFinal(bool b) { isFinal_ = b; } + bool isFinal() const { return isFinal_; } + private: void addAssociatedProperty(PropertyNode* property); @@ -964,6 +996,9 @@ private: bool attached_: 1; bool privateSignal_: 1; bool overload_ : 1; + bool isDeleted_ : 1; + bool isDefaulted_ : 1; + bool isFinal_ : 1; unsigned char overloadNumber_; QVector<Parameter> parameters_; const FunctionNode* reimplementedFrom_; @@ -971,97 +1006,6 @@ private: QList<FunctionNode*> reimplementedBy_; }; -enum ParseResult { Ignore, SyntaxError, Function, Variable }; - -class Declaration -{ - public: - Declaration() - : result_(Ignore), parent_(0), type_(Node::Function), access_(Node::Public), - metaness_(FunctionNode::Plain), bodyExpected_(false), bodyPresent_(false), - isAttached_(false), isMacro_(false), isQPrivateSignal_(false), isQT_DEPRECATED_(false), - isFriend_(false), isStatic_(false), isInline_(false), isExplicit_(false), isCompat_(false), - isConst_(false), virtuality_(FunctionNode::NonVirtual) { } - - Declaration(Aggregate* p) - : result_(Ignore), parent_(p), type_(Node::Function), access_(Node::Public), - metaness_(FunctionNode::Plain), bodyExpected_(false), bodyPresent_(false), - isAttached_(false), isMacro_(false), isQPrivateSignal_(false), isQT_DEPRECATED_(false), - isFriend_(false), isStatic_(false), isInline_(false), isExplicit_(false), isCompat_(false), - isConst_(false), virtuality_(FunctionNode::NonVirtual) { } - - Declaration(Aggregate* p, Node::NodeType t, bool isAttached) - : result_(Ignore), parent_(p), type_(t), access_(Node::Public), - metaness_(FunctionNode::Plain), bodyExpected_(false), bodyPresent_(false), - isAttached_(isAttached), isMacro_(false), isQPrivateSignal_(false), isQT_DEPRECATED_(false), - isFriend_(false), isStatic_(false), isInline_(false), isExplicit_(false), isCompat_(false), - isConst_(false), virtuality_(FunctionNode::NonVirtual) { } - - Declaration(Aggregate* p, const QString& t) - : result_(Ignore), parent_(p), templateStuff_(t), type_(Node::Function), access_(Node::Public), - metaness_(FunctionNode::Plain), bodyExpected_(false), bodyPresent_(false), - isAttached_(false), isMacro_(false), isQPrivateSignal_(false), isQT_DEPRECATED_(false), - isFriend_(false), isStatic_(false), isInline_(false), isExplicit_(false), isCompat_(false), - isConst_(false), virtuality_(FunctionNode::NonVirtual) { } - - Declaration(Aggregate* p, bool isMacro) - : result_(Ignore), parent_(p), type_(Node::Function), access_(Node::Public), - metaness_(FunctionNode::Plain), bodyExpected_(false), bodyPresent_(false), - isAttached_(false), isMacro_(isMacro), isQPrivateSignal_(false), isQT_DEPRECATED_(false), - isFriend_(false), isStatic_(false), isInline_(false), isExplicit_(false), isCompat_(false), - isConst_(false), virtuality_(FunctionNode::NonVirtual) { } - - void clear() { - parent_ = 0; - type_ = Node::Function; - access_ = Node::Public; - metaness_ = FunctionNode::Plain; - bodyExpected_ = false; - bodyPresent_ = false; - isAttached_ = false; - isMacro_ = false; - isQPrivateSignal_ = false; - isQT_DEPRECATED_ = false; - isFriend_ = false; - isStatic_ = false; - isInline_ = false; - isExplicit_ = false; - isCompat_ = false; - isConst_ = false; - virtuality_ = FunctionNode::NonVirtual; - } - - bool ignoreThisDecl() const { return (isFriend_ && !bodyPresent_); } - bool isFunction() const { return (result_ == Function); } - bool isVariable() const { return (result_ == Variable); } - - public: - ParseResult result_; - Aggregate* parent_; - QStringList parentPath_; - QString name_; - QString templateStuff_; - Node::NodeType type_; - Node::Access access_; - FunctionNode::Metaness metaness_; - bool bodyExpected_; - bool bodyPresent_; - bool isAttached_; - bool isMacro_; - bool isQPrivateSignal_; - bool isQT_DEPRECATED_; - bool isFriend_; - bool isStatic_; - bool isInline_; - bool isExplicit_; - bool isCompat_; - bool isConst_; - FunctionNode::Virtualness virtuality_; - CodeChunk returnType_; - Location location_; - QVector<Parameter> pvect_; -}; - class PropertyNode : public LeafNode { public: diff --git a/src/qdoc/qdoc.pro b/src/qdoc/qdoc.pro index 6333a046e..52b40bccb 100644 --- a/src/qdoc/qdoc.pro +++ b/src/qdoc/qdoc.pro @@ -4,7 +4,12 @@ } option(host_build) -QT = core qmldevtools-private +QT = core +qtHaveModule(qmldevtools-private) { + QT += qmldevtools-private +} else { + DEFINES += QT_NO_DECLARATIVE +} DEFINES += \ QDOC2_COMPAT diff --git a/src/qdoc/qdocdatabase.cpp b/src/qdoc/qdocdatabase.cpp index 795da4484..37ccd3220 100644 --- a/src/qdoc/qdocdatabase.cpp +++ b/src/qdoc/qdocdatabase.cpp @@ -68,9 +68,8 @@ bool QDocDatabase::debug = false; */ QDocForest::~QDocForest() { - for (int i=0; i<searchOrder_.size(); ++i) { + for (int i=0; i<searchOrder_.size(); ++i) delete searchOrder_.at(i); - } forest_.clear(); searchOrder_.clear(); indexSearchOrder_.clear(); @@ -783,6 +782,30 @@ QmlTypeNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name) } /*! + Looks up the QML basic type node identified by the Qml module id + \a qmid and QML basic type \a name and returns a pointer to the + QML basic type node. The key is \a qmid + "::" + \a name. + + If the QML module id is empty, it looks up the QML basic type by + \a name only. + */ +Aggregate* QDocDatabase::findQmlBasicType(const QString& qmid, const QString& name) +{ + if (!qmid.isEmpty()) { + QString t = qmid + "::" + name; + Aggregate* a = forest_.lookupQmlBasicType(t); + if (a) + return a; + } + + QStringList path(name); + Node* n = forest_.findNodeByNameAndType(path, Node::QmlBasicType); + if (n && n->isQmlBasicType()) + return static_cast<Aggregate*>(n); + return 0; +} + +/*! Looks up the QML type node identified by the Qml module id constructed from the strings in the \a import record and the QML type \a name and returns a pointer to the QML type node. @@ -1026,10 +1049,8 @@ void QDocDatabase::findAllFunctions(Aggregate* node) } else if ((*c)->type() == Node::Function) { const FunctionNode* func = static_cast<const FunctionNode*>(*c); - if ((func->status() > Node::Obsolete) && - !func->isInternal() && - (func->metaness() != FunctionNode::Ctor) && - (func->metaness() != FunctionNode::Dtor)) { + if ((func->status() > Node::Obsolete) && !func->isInternal() && + !func->isSomeCtor() && !func->isDtor()) { funcIndex_[(*c)->name()].insert((*c)->parent()->fullDocumentName(), *c); } } @@ -1203,9 +1224,7 @@ void QDocDatabase::findAllSince(Aggregate* node) if ((*child)->type() == Node::Function) { // Insert functions into the general since map. FunctionNode *func = static_cast<FunctionNode *>(*child); - if ((func->status() > Node::Obsolete) && - (func->metaness() != FunctionNode::Ctor) && - (func->metaness() != FunctionNode::Dtor)) { + if ((func->status() > Node::Obsolete) && !func->isSomeCtor() && !func->isDtor()) { nsmap.value().insert(func->name(),(*child)); } } @@ -1387,7 +1406,16 @@ void QDocDatabase::resolveNamespaces() } } } - +#if 0 +/*! + */ +const Node* QDocDatabase::findFunctionNode(const QString& target, + const Node* relative, + Node::Genus genus) +{ + return forest_.findFunctionNode(target, relative, genus); +} +#endif /*! This function is called for autolinking to a \a type, which could be a function return type or a parameter @@ -1527,9 +1555,9 @@ void QDocDatabase::generateIndex(const QString& fileName, } /*! - If there are open namespaces, search each one for a function - node having the same function name as the function described - in \a declData. The \a parentPath is a portion of the path + If there are open namespaces, search for the function node + having the same function name as the \a clone node in each + open namespace. The \a parentPath is a portion of the path name provided with the function name at the point of reference. \a parentPath is usually a class name. Return the pointer to the function node if one is found in an @@ -1539,13 +1567,13 @@ void QDocDatabase::generateIndex(const QString& fileName, be removed. */ FunctionNode* QDocDatabase::findNodeInOpenNamespace(const QStringList& parentPath, - const Declaration& declData) + const FunctionNode* clone) { FunctionNode* fn = 0; if (!openNamespaces_.isEmpty()) { foreach (const QString& t, openNamespaces_) { QStringList path = t.split("::") + parentPath; - fn = findFunctionNode(path, declData); + fn = findFunctionNode(path, clone); if (fn) break; } diff --git a/src/qdoc/qdocdatabase.h b/src/qdoc/qdocdatabase.h index 941c7b61b..5a6ccd7c0 100644 --- a/src/qdoc/qdocdatabase.h +++ b/src/qdoc/qdocdatabase.h @@ -189,6 +189,16 @@ class QDocForest } return 0; } + + Aggregate* lookupQmlBasicType(const QString& name) + { + foreach (Tree* t, searchOrder()) { + Aggregate* a = t->lookupQmlBasicType(name); + if (a) + return a; + } + return 0; + } void clearSearchOrder() { searchOrder_.clear(); } void clearLinkCounts() { @@ -253,6 +263,7 @@ class QDocDatabase QmlTypeNode* findQmlType(const QString& name); QmlTypeNode* findQmlType(const QString& qmid, const QString& name); QmlTypeNode* findQmlType(const ImportRec& import, const QString& name); + Aggregate* findQmlBasicType(const QString& qmid, const QString& name); private: void findAllClasses(Aggregate *node); @@ -302,10 +313,10 @@ class QDocDatabase /******************************************************************* The functions declared below are called for the current tree only. ********************************************************************/ - FunctionNode* findFunctionNode(const QStringList& parentPath, const Declaration& declData) { - return primaryTree()->findFunctionNode(parentPath, declData); + FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone) { + return primaryTree()->findFunctionNode(parentPath, clone); } - FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const Declaration& declData); + FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone); Node* findNodeInOpenNamespace(QStringList& path, Node::NodeType type); const Node* checkForCollision(const QString& name) { return primaryTree()->checkForCollision(name); diff --git a/src/qdoc/qdocindexfiles.cpp b/src/qdoc/qdocindexfiles.cpp index 25bfa259e..c8439d39d 100644 --- a/src/qdoc/qdocindexfiles.cpp +++ b/src/qdoc/qdocindexfiles.cpp @@ -485,44 +485,15 @@ void QDocIndexFiles::readIndexSection(QXmlStreamReader& reader, } else if (elementName == QLatin1String("function")) { - FunctionNode::Virtualness virt; - QString t = attributes.value(QLatin1String("virtual")).toString(); - if (t == QLatin1String("non")) - virt = FunctionNode::NonVirtual; - else if (t == QLatin1String("virtual")) - virt = FunctionNode::NormalVirtual; - else if (t == QLatin1String("pure")) - virt = FunctionNode::PureVirtual; - else - goto done; - - t = attributes.value(QLatin1String("meta")).toString(); - FunctionNode::Metaness meta; - if (t == QLatin1String("plain")) - meta = FunctionNode::Plain; - else if (t == QLatin1String("signal")) - meta = FunctionNode::Signal; - else if (t == QLatin1String("slot")) - meta = FunctionNode::Slot; - else if (t == QLatin1String("constructor")) - meta = FunctionNode::Ctor; - else if (t == QLatin1String("destructor")) - meta = FunctionNode::Dtor; - else if (t == QLatin1String("macro")) - meta = FunctionNode::MacroWithParams; - else if (t == QLatin1String("macrowithparams")) - meta = FunctionNode::MacroWithParams; - else if (t == QLatin1String("macrowithoutparams")) - meta = FunctionNode::MacroWithoutParams; - else - goto done; - FunctionNode* functionNode = new FunctionNode(parent, name); functionNode->setReturnType(attributes.value(QLatin1String("return")).toString()); - functionNode->setVirtualness(virt); - functionNode->setMetaness(meta); + functionNode->setVirtualness(attributes.value(QLatin1String("virtual")).toString()); + functionNode->setMetaness(attributes.value(QLatin1String("meta")).toString()); functionNode->setConst(attributes.value(QLatin1String("const")) == QLatin1String("true")); functionNode->setStatic(attributes.value(QLatin1String("static")) == QLatin1String("true")); + functionNode->setIsDeleted(attributes.value(QLatin1String("delete")) == QLatin1String("true")); + functionNode->setIsDefaulted(attributes.value(QLatin1String("default")) == QLatin1String("true")); + functionNode->setFinal(attributes.value(QLatin1String("final")) == QLatin1String("true")); if (attributes.value(QLatin1String("overload")) == QLatin1String("true")) { functionNode->setOverloadFlag(true); functionNode->setOverloadNumber(attributes.value(QLatin1String("overload-number")).toUInt()); @@ -1203,48 +1174,14 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, function being described. */ const FunctionNode* functionNode = static_cast<const FunctionNode*>(node); - switch (functionNode->virtualness()) { - case FunctionNode::NonVirtual: - writer.writeAttribute("virtual", "non"); - break; - case FunctionNode::NormalVirtual: - writer.writeAttribute("virtual", "virtual"); - break; - case FunctionNode::PureVirtual: - writer.writeAttribute("virtual", "pure"); - break; - default: - break; - } - - switch (functionNode->metaness()) { - case FunctionNode::Plain: - writer.writeAttribute("meta", "plain"); - break; - case FunctionNode::Signal: - writer.writeAttribute("meta", "signal"); - break; - case FunctionNode::Slot: - writer.writeAttribute("meta", "slot"); - break; - case FunctionNode::Ctor: - writer.writeAttribute("meta", "constructor"); - break; - case FunctionNode::Dtor: - writer.writeAttribute("meta", "destructor"); - break; - case FunctionNode::MacroWithParams: - writer.writeAttribute("meta", "macrowithparams"); - break; - case FunctionNode::MacroWithoutParams: - writer.writeAttribute("meta", "macrowithoutparams"); - break; - default: - break; - } + writer.writeAttribute("virtual", functionNode->virtualness()); + writer.writeAttribute("meta", functionNode->metaness()); writer.writeAttribute("const", functionNode->isConst()?"true":"false"); writer.writeAttribute("static", functionNode->isStatic()?"true":"false"); writer.writeAttribute("overload", functionNode->isOverload()?"true":"false"); + writer.writeAttribute("delete", functionNode->isDeleted() ? "true" : "false"); + writer.writeAttribute("default", functionNode->isDefaulted() ? "true" : "false"); + writer.writeAttribute("final", functionNode->isFinal() ? "true" : "false"); if (functionNode->isOverload()) writer.writeAttribute("overload-number", QString::number(functionNode->overloadNumber())); if (functionNode->relates()) { @@ -1270,6 +1207,14 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, QString signature = functionNode->signature(false); if (functionNode->isConst()) signature += " const"; + if (functionNode->isFinal()) + signature += " final"; + if (functionNode->isPureVirtual()) + signature += " = 0"; + else if (functionNode->isDeleted()) + signature += " = delete"; + else if (functionNode->isDefaulted()) + signature += " = default"; writer.writeAttribute("signature", signature); for (int i = 0; i < functionNode->parameters().size(); ++i) { diff --git a/src/qdoc/qdoctagfiles.cpp b/src/qdoc/qdoctagfiles.cpp index 26f5342c1..115fcb63d 100644 --- a/src/qdoc/qdoctagfiles.cpp +++ b/src/qdoc/qdoctagfiles.cpp @@ -262,23 +262,10 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const Aggreg const FunctionNode* functionNode = static_cast<const FunctionNode*>(node); writer.writeAttribute("protection", access); - - switch (functionNode->virtualness()) { - case FunctionNode::NonVirtual: - writer.writeAttribute("virtualness", "non"); - break; - case FunctionNode::NormalVirtual: - writer.writeAttribute("virtualness", "virtual"); - break; - case FunctionNode::PureVirtual: - writer.writeAttribute("virtual", "pure"); - break; - default: - break; - } + writer.writeAttribute("virtualness", functionNode->virtualness()); writer.writeAttribute("static", functionNode->isStatic() ? "yes" : "no"); - if (functionNode->virtualness() == FunctionNode::NonVirtual) + if (functionNode->isNonvirtual()) writer.writeTextElement("type", functionNode->returnType()); else writer.writeTextElement("type", "virtual " + functionNode->returnType()); @@ -291,8 +278,14 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const Aggreg signature = signature.mid(signature.indexOf(QChar('('))).trimmed(); if (functionNode->isConst()) signature += " const"; - if (functionNode->virtualness() == FunctionNode::PureVirtual) + if (functionNode->isFinal()) + signature += " final"; + if (functionNode->isPureVirtual()) signature += " = 0"; + else if (functionNode->isDeleted()) + signature += " = delete"; + else if (functionNode->isDefaulted()) + signature += " = default"; writer.writeTextElement("arglist", signature); } writer.writeEndElement(); // member diff --git a/src/qdoc/qmlcodemarker.cpp b/src/qdoc/qmlcodemarker.cpp index 089e1d1c8..3b76f87da 100644 --- a/src/qdoc/qmlcodemarker.cpp +++ b/src/qdoc/qmlcodemarker.cpp @@ -44,11 +44,13 @@ #include "tree.h" #include "generator.h" +#ifndef QT_NO_DECLARATIVE #include <private/qqmljsast_p.h> #include <private/qqmljsastfwd_p.h> #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> +#endif QT_BEGIN_NAMESPACE @@ -65,6 +67,7 @@ QmlCodeMarker::~QmlCodeMarker() */ bool QmlCodeMarker::recognizeCode(const QString &code) { +#ifndef QT_NO_DECLARATIVE QQmlJS::Engine engine; QQmlJS::Lexer lexer(&engine); QQmlJS::Parser parser(&engine); @@ -74,6 +77,9 @@ bool QmlCodeMarker::recognizeCode(const QString &code) lexer.setCode(newCode, 1); return parser.parse(); +#else + return false; +#endif } /*! @@ -163,6 +169,7 @@ QString QmlCodeMarker::addMarkUp(const QString &code, const Node * /* relative */, const Location &location) { +#ifndef QT_NO_DECLARATIVE QQmlJS::Engine engine; QQmlJS::Lexer lexer(&engine); @@ -188,8 +195,13 @@ QString QmlCodeMarker::addMarkUp(const QString &code, } return output; +#else + location.warning("QtDeclarative not installed; cannot parse QML or JS."); + return QString(); +#endif } +#ifndef QT_NO_DECLARATIVE /* Copied and pasted from src/declarative/qml/qqmlscriptparser.cpp. @@ -270,5 +282,6 @@ QList<QQmlJS::AST::SourceLocation> QmlCodeMarker::extractPragmas(QString &script } return removed; } +#endif QT_END_NAMESPACE diff --git a/src/qdoc/qmlcodemarker.h b/src/qdoc/qmlcodemarker.h index 96353ebe5..0090350e7 100644 --- a/src/qdoc/qmlcodemarker.h +++ b/src/qdoc/qmlcodemarker.h @@ -40,7 +40,9 @@ #include "cppcodemarker.h" +#ifndef QT_NO_DECLARATIVE #include <private/qqmljsastfwd_p.h> +#endif QT_BEGIN_NAMESPACE @@ -67,7 +69,9 @@ public: virtual QString functionEndRegExp(const QString &funcName) Q_DECL_OVERRIDE; /* Copied from src/declarative/qml/qdeclarativescriptparser.cpp */ +#ifndef QT_NO_DECLARATIVE QList<QQmlJS::AST::SourceLocation> extractPragmas(QString &script); +#endif private: QString addMarkUp(const QString &code, const Node *relative, diff --git a/src/qdoc/qmlcodeparser.cpp b/src/qdoc/qmlcodeparser.cpp index e94df4753..58be80d01 100644 --- a/src/qdoc/qmlcodeparser.cpp +++ b/src/qdoc/qmlcodeparser.cpp @@ -41,8 +41,10 @@ #include "config.h" #include "qmlvisitor.h" +#ifndef QT_NO_DECLARATIVE #include <private/qqmljsast_p.h> #include <private/qqmljsastvisitor_p.h> +#endif #include <qdebug.h> QT_BEGIN_NAMESPACE @@ -97,8 +99,10 @@ QT_BEGIN_NAMESPACE Constructs the QML code parser. */ QmlCodeParser::QmlCodeParser() +#ifndef QT_NO_DECLARATIVE : lexer( 0 ), parser( 0 ) +#endif { } @@ -119,8 +123,10 @@ void QmlCodeParser::initializeParser(const Config &config) { CodeParser::initializeParser(config); +#ifndef QT_NO_DECLARATIVE lexer = new QQmlJS::Lexer(&engine); parser = new QQmlJS::Parser(&engine); +#endif } /*! @@ -129,8 +135,10 @@ void QmlCodeParser::initializeParser(const Config &config) */ void QmlCodeParser::terminateParser() { +#ifndef QT_NO_DECLARATIVE delete lexer; delete parser; +#endif } /*! @@ -167,6 +175,7 @@ void QmlCodeParser::parseSourceFile(const Location& location, const QString& fil return; } +#ifndef QT_NO_DECLARATIVE QString document = in.readAll(); in.close(); @@ -195,6 +204,9 @@ void QmlCodeParser::parseSourceFile(const Location& location, const QString& fil << ": " << qPrintable(msg.message); } currentFile_.clear(); +#else + location.warning("QtDeclarative not installed; cannot parse QML or JS."); +#endif } /*! @@ -265,6 +277,7 @@ const QSet<QString>& QmlCodeParser::otherMetaCommands() return otherMetaCommands_; } +#ifndef QT_NO_DECLARATIVE /*! Copy and paste from src/declarative/qml/qdeclarativescriptparser.cpp. This function blanks out the section of the \a str beginning at \a idx @@ -329,5 +342,6 @@ void QmlCodeParser::extractPragmas(QString &script) } return; } +#endif QT_END_NAMESPACE diff --git a/src/qdoc/qmlcodeparser.h b/src/qdoc/qmlcodeparser.h index 8b5667532..f483b7382 100644 --- a/src/qdoc/qmlcodeparser.h +++ b/src/qdoc/qmlcodeparser.h @@ -41,9 +41,11 @@ #include "codeparser.h" #include <qset.h> +#ifndef QT_NO_DECLARATIVE #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> #include <private/qqmljsparser_p.h> +#endif QT_BEGIN_NAMESPACE @@ -66,17 +68,21 @@ public: virtual void parseSourceFile(const Location& location, const QString& filePath) Q_DECL_OVERRIDE; virtual void doneParsingSourceFiles() Q_DECL_OVERRIDE; +#ifndef QT_NO_DECLARATIVE /* Copied from src/declarative/qml/qdeclarativescriptparser.cpp */ void extractPragmas(QString &script); +#endif protected: const QSet<QString>& topicCommands(); const QSet<QString>& otherMetaCommands(); private: +#ifndef QT_NO_DECLARATIVE QQmlJS::Engine engine; QQmlJS::Lexer *lexer; QQmlJS::Parser *parser; +#endif }; QT_END_NAMESPACE diff --git a/src/qdoc/qmlmarkupvisitor.cpp b/src/qdoc/qmlmarkupvisitor.cpp index 17dd99325..122c23040 100644 --- a/src/qdoc/qmlmarkupvisitor.cpp +++ b/src/qdoc/qmlmarkupvisitor.cpp @@ -35,12 +35,15 @@ #include <qstringlist.h> #include <qglobal.h> +#ifndef QT_NO_DECLARATIVE #include <private/qqmljsast_p.h> #include <private/qqmljsastfwd_p.h> #include <private/qqmljsengine_p.h> +#endif QT_BEGIN_NAMESPACE +#ifndef QT_NO_DECLARATIVE QmlMarkupVisitor::QmlMarkupVisitor(const QString &source, const QList<QQmlJS::AST::SourceLocation> &pragmas, QQmlJS::Engine *engine) @@ -840,5 +843,6 @@ bool QmlMarkupVisitor::visit(QQmlJS::AST::UiObjectDefinition *definition) QQmlJS::AST::Node::accept(definition->initializer, this); return false; } +#endif QT_END_NAMESPACE diff --git a/src/qdoc/qmlmarkupvisitor.h b/src/qdoc/qmlmarkupvisitor.h index ab1180fd4..63d6f1bf4 100644 --- a/src/qdoc/qmlmarkupvisitor.h +++ b/src/qdoc/qmlmarkupvisitor.h @@ -38,11 +38,14 @@ #include "tree.h" #include <qstring.h> +#ifndef QT_NO_DECLARATIVE #include <private/qqmljsastvisitor_p.h> #include <private/qqmljsengine_p.h> +#endif QT_BEGIN_NAMESPACE +#ifndef QT_NO_DECLARATIVE class QmlMarkupVisitor : public QQmlJS::AST::Visitor { public: @@ -167,6 +170,7 @@ private: int extraIndex; }; Q_DECLARE_TYPEINFO(QmlMarkupVisitor::ExtraType, Q_PRIMITIVE_TYPE); +#endif QT_END_NAMESPACE diff --git a/src/qdoc/qmlvisitor.cpp b/src/qdoc/qmlvisitor.cpp index 654922929..3fee46932 100644 --- a/src/qdoc/qmlvisitor.cpp +++ b/src/qdoc/qmlvisitor.cpp @@ -42,9 +42,11 @@ #include <qstringlist.h> #include <qglobal.h> #include <qdebug.h> +#ifndef QT_NO_DECLARATIVE #include <private/qqmljsast_p.h> #include <private/qqmljsastfwd_p.h> #include <private/qqmljsengine_p.h> +#endif QT_BEGIN_NAMESPACE @@ -89,6 +91,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_JSATTACHEDMETHOD Doc::alias(QLatin1String("jsattachedmethod")) #define COMMAND_JSBASICTYPE Doc::alias(QLatin1String("jsbasictype")) +#ifndef QT_NO_DECLARATIVE /*! The constructor stores all the parameters in local data members. */ @@ -823,5 +826,6 @@ void QmlDocVisitor::endVisit(QQmlJS::AST::UiQualifiedId* ) { // nothing. } +#endif QT_END_NAMESPACE diff --git a/src/qdoc/qmlvisitor.h b/src/qdoc/qmlvisitor.h index 8a23eef75..bc7a3c003 100644 --- a/src/qdoc/qmlvisitor.h +++ b/src/qdoc/qmlvisitor.h @@ -37,8 +37,10 @@ #include "node.h" #include <qstring.h> +#ifndef QT_NO_DECLARATIVE #include <private/qqmljsastvisitor_p.h> #include <private/qqmljsengine_p.h> +#endif QT_BEGIN_NAMESPACE @@ -57,6 +59,7 @@ struct QmlPropArgs } }; +#ifndef QT_NO_DECLARATIVE class QmlDocVisitor : public QQmlJS::AST::Visitor { Q_DECLARE_TR_FUNCTIONS(QDoc::QmlDocVisitor) @@ -115,6 +118,7 @@ private: QSet<quint32> usedComments; Aggregate *current; }; +#endif QT_END_NAMESPACE diff --git a/src/qdoc/tokenizer.cpp b/src/qdoc/tokenizer.cpp index b2cd906e6..f723debe7 100644 --- a/src/qdoc/tokenizer.cpp +++ b/src/qdoc/tokenizer.cpp @@ -55,12 +55,11 @@ QT_BEGIN_NAMESPACE */ static const char *kwords[] = { "char", "class", "const", "double", "enum", "explicit", - "friend", "inline", "int", "long", "namespace", "noexcept", - "operator", "private", "protected", "public", "short", - "signals", "signed", "slots", "static", "struct", "template", - "throw", "typedef", "typename", "union", "unsigned", "using", - "virtual", "void", "volatile", - "__int64", + "friend", "inline", "int", "long", "namespace", "operator", + "private", "protected", "public", "short", "signals", "signed", + "slots", "static", "struct", "template", "typedef", "typename", + "union", "unsigned", "using", "virtual", "void", "volatile", + "__int64", "default", "delete", "final", "Q_OBJECT", "Q_OVERRIDE", "Q_PROPERTY", diff --git a/src/qdoc/tokenizer.h b/src/qdoc/tokenizer.h index 456be7335..2f293379f 100644 --- a/src/qdoc/tokenizer.h +++ b/src/qdoc/tokenizer.h @@ -62,11 +62,12 @@ enum { Tok_Eoi, Tok_Ampersand, Tok_Aster, Tok_Caret, Tok_LeftParen, Tok_Number, Tok_String, Tok_Doc, Tok_Comment, Tok_Ident, Tok_At, Tok_char, Tok_class, Tok_const, Tok_double, Tok_enum, Tok_explicit, Tok_friend, Tok_inline, Tok_int, Tok_long, - Tok_namespace, Tok_noexcept, Tok_operator, Tok_private, Tok_protected, + Tok_namespace, Tok_operator, Tok_private, Tok_protected, Tok_public, Tok_short, Tok_signals, Tok_signed, Tok_slots, - Tok_static, Tok_struct, Tok_template, Tok_throw, Tok_typedef, + Tok_static, Tok_struct, Tok_template, Tok_typedef, Tok_typename, Tok_union, Tok_unsigned, Tok_using, Tok_virtual, - Tok_void, Tok_volatile, Tok_int64, Tok_Q_OBJECT, Tok_Q_OVERRIDE, + Tok_void, Tok_volatile, Tok_int64, Tok_default, Tok_delete, Tok_final, + Tok_Q_OBJECT, Tok_Q_OVERRIDE, Tok_Q_PROPERTY, Tok_Q_PRIVATE_PROPERTY, Tok_Q_DECLARE_SEQUENTIAL_ITERATOR, Tok_Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR, Tok_Q_DECLARE_ASSOCIATIVE_ITERATOR, diff --git a/src/qdoc/tree.cpp b/src/qdoc/tree.cpp index 10b46f712..39d838333 100644 --- a/src/qdoc/tree.cpp +++ b/src/qdoc/tree.cpp @@ -102,8 +102,6 @@ Tree::Tree(const QString& camelCaseModuleName, QDocDatabase* qdb) */ Tree::~Tree() { - if (Generator::debugging()) - qDebug() << " Deleting tree:" << physicalModuleName_; TargetMap::iterator i = nodesByTargetRef_.begin(); while (i != nodesByTargetRef_.end()) { delete i.value(); @@ -123,8 +121,6 @@ Tree::~Tree() ++i; } } - if (Generator::debugging()) - qDebug() << " Deleted tree:" << physicalModuleName_; } /* API members */ @@ -168,18 +164,17 @@ NamespaceNode* Tree::findNamespaceNode(const QStringList& path) const } /*! - This function first ignores the \a declData parameter and - searches for the parent node with \a parentPath. If that - search is successful, it searches for a child node of the - parent that matches the function described in \a declData. - If it finds a match, it returns a pointer to the matching - node. + This function first ignores the \a clone node and searches + for the parent node with \a parentPath. If that search is + successful, it searches for a child node of the parent that + matches the \a clone node. If it finds a node that is just + like the \a clone, it returns a pointer to the found node. Apparently the search order is important here. Don't change it unless you know what you are doing, or you will introduce qdoc warnings. */ -FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, const Declaration& declData) +FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, const FunctionNode* clone) { const Node* parent = findNamespaceNode(parentPath); if (parent == 0) @@ -188,7 +183,7 @@ FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, const Declar parent = findNode(parentPath, 0, 0, Node::DontCare); if (parent == 0 || !parent->isAggregate()) return 0; - return ((const Aggregate*)parent)->findFunctionNode(declData); + return ((const Aggregate*)parent)->findFunctionNode(clone); } @@ -429,8 +424,8 @@ void Tree::resolveInheritanceHelper(int pass, ClassNode* cn) FunctionNode* func = (FunctionNode*)* c; FunctionNode* from = findVirtualFunctionInBaseClasses(cn, func); if (from != 0) { - if (func->virtualness() == FunctionNode::NonVirtual) - func->setVirtualness(FunctionNode::NormalVirtual); + if (func->isNonvirtual()) + func->setVirtual(); func->setReimplementedFrom(from); } } @@ -556,16 +551,16 @@ void Tree::fixInheritance(NamespaceNode* rootNode) /*! */ -FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* cn, FunctionNode* virtualFunc) +FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* cn, FunctionNode* clone) { const QList<RelatedClass>& rc = cn->baseClasses(); QList<RelatedClass>::ConstIterator r = rc.constBegin(); while (r != rc.constEnd()) { FunctionNode* func; if ((*r).node_) { - if (((func = findVirtualFunctionInBaseClasses((*r).node_, virtualFunc)) != 0 || - (func = (*r).node_->findFunctionNode(virtualFunc)) != 0)) { - if (func->virtualness() != FunctionNode::NonVirtual) + if (((func = findVirtualFunctionInBaseClasses((*r).node_, clone)) != 0 || + (func = (*r).node_->findFunctionNode(clone)) != 0)) { + if (!func->isNonvirtual()) return func; } } @@ -739,7 +734,7 @@ const Node* Tree::findNodeForTarget(const QStringList& path, } } - node = findUnambiguousTarget(path.join(QStringLiteral("::")), ref); + node = findUnambiguousTarget(path.join(QStringLiteral("::")), genus, ref); if (node) { if (!target.isEmpty()) { ref = getRef(target, node); @@ -1070,7 +1065,7 @@ void Tree::resolveTargets(Aggregate* root) finds one, it sets \a ref and returns the found node. */ const Node* -Tree::findUnambiguousTarget(const QString& target, QString& ref) const +Tree::findUnambiguousTarget(const QString& target, Node::Genus genus, QString& ref) const { int numBestTargets = 0; TargetRec* bestTarget = 0; @@ -1082,14 +1077,17 @@ Tree::findUnambiguousTarget(const QString& target, QString& ref) const if (i.key() != key) break; TargetRec* candidate = i.value(); - if (!bestTarget || (candidate->priority_ < bestTarget->priority_)) { - bestTarget = candidate; - bestTargetList.clear(); - bestTargetList.append(candidate); - numBestTargets = 1; - } else if (candidate->priority_ == bestTarget->priority_) { - bestTargetList.append(candidate); - ++numBestTargets; + if ((genus == Node::DontCare) || (genus == candidate->genus())) { + if (!bestTarget || (candidate->priority_ < bestTarget->priority_)) { + bestTarget = candidate; + bestTargetList.clear(); + bestTargetList.append(candidate); + numBestTargets = 1; + } + else if (candidate->priority_ == bestTarget->priority_) { + bestTargetList.append(candidate); + ++numBestTargets; + } } ++i; } @@ -1106,14 +1104,17 @@ Tree::findUnambiguousTarget(const QString& target, QString& ref) const if (i.key() != key) break; TargetRec* candidate = i.value(); - if (!bestTarget || (candidate->priority_ < bestTarget->priority_)) { - bestTarget = candidate; - bestTargetList.clear(); - bestTargetList.append(candidate); - numBestTargets = 1; - } else if (candidate->priority_ == bestTarget->priority_) { - bestTargetList.append(candidate); - ++numBestTargets; + if ((genus == Node::DontCare) || (genus == candidate->genus())) { + if (!bestTarget || (candidate->priority_ < bestTarget->priority_)) { + bestTarget = candidate; + bestTargetList.clear(); + bestTargetList.append(candidate); + numBestTargets = 1; + } + else if (candidate->priority_ == bestTarget->priority_) { + bestTargetList.append(candidate); + ++numBestTargets; + } } ++i; } @@ -1466,7 +1467,7 @@ const Node* Tree::findFunctionNode(const QString& target, } QStringList path = t.split("::"); const FunctionNode* fn = findFunctionNode(path, params, relative, SearchBaseClasses, genus); - if (fn && fn->metaness() != FunctionNode::MacroWithoutParams) + if (fn && !fn->isMacroWithoutParams()) return fn; return 0; } diff --git a/src/qdoc/tree.h b/src/qdoc/tree.h index 649400e78..1c6ebcf41 100644 --- a/src/qdoc/tree.h +++ b/src/qdoc/tree.h @@ -64,6 +64,7 @@ struct TargetRec } bool isEmpty() const { return ref_.isEmpty(); } + Node::Genus genus() { return (node_ ? node_->genus() : Node::DontCare); } Node* node_; QString ref_; @@ -106,7 +107,7 @@ class Tree Node* findNodeForInclude(const QStringList& path) const; ClassNode* findClassNode(const QStringList& path, const Node* start = 0) const; NamespaceNode* findNamespaceNode(const QStringList& path) const; - FunctionNode* findFunctionNode(const QStringList& parentPath, const Declaration& declData); + FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone); const Node* findFunctionNode(const QString& target, const QString& params, const Node* relative, @@ -151,7 +152,7 @@ class Tree Node* node, int priority); void resolveTargets(Aggregate* root); - const Node* findUnambiguousTarget(const QString& target, QString& ref) const; + const Node* findUnambiguousTarget(const QString& target, Node::Genus genus, QString& ref) const; const DocumentNode* findDocumentNodeByTitle(const QString& title) const; void addPropertyFunction(PropertyNode *property, @@ -173,7 +174,7 @@ class Tree const NamespaceNode *root() const { return &root_; } FunctionNode *findVirtualFunctionInBaseClasses(ClassNode *classe, - FunctionNode *virtualFunc); + FunctionNode *clone); NodeList allBaseClasses(const ClassNode *classe) const; QString refForAtom(const Atom* atom); @@ -202,6 +203,7 @@ class Tree CollectionNode* addToJsModule(const QString& name, Node* node); QmlTypeNode* lookupQmlType(const QString& name) const { return qmlTypeMap_.value(name); } + Aggregate* lookupQmlBasicType(const QString& name) const { return qmlTypeMap_.value(name); } void insertQmlType(const QString& key, QmlTypeNode* n); void addExampleNode(ExampleNode* n) { exampleNodeMap_.insert(n->title(), n); } ExampleNodeMap& exampleNodeMap() { return exampleNodeMap_; } diff --git a/src/qtdiag/main.cpp b/src/qtdiag/main.cpp index 6bc42bc2c..7e304d401 100644 --- a/src/qtdiag/main.cpp +++ b/src/qtdiag/main.cpp @@ -53,14 +53,18 @@ int main(int argc, char **argv) QCommandLineParser commandLineParser; const QCommandLineOption noGlOption(QStringLiteral("no-gl"), QStringLiteral("Do not output GL information")); const QCommandLineOption glExtensionOption(QStringLiteral("gl-extensions"), QStringLiteral("List GL extensions")); + const QCommandLineOption fontOption(QStringLiteral("fonts"), QStringLiteral("Output list of fonts")); commandLineParser.setApplicationDescription(QStringLiteral("Prints diagnostic output about the Qt library.")); commandLineParser.addOption(noGlOption); commandLineParser.addOption(glExtensionOption); + commandLineParser.addOption(fontOption); commandLineParser.addHelpOption(); commandLineParser.process(app); unsigned flags = commandLineParser.isSet(noGlOption) ? 0u : unsigned(QtDiagGl); if (commandLineParser.isSet(glExtensionOption)) flags |= QtDiagGlExtensions; + if (commandLineParser.isSet(fontOption)) + flags |= QtDiagFonts; std::wcout << qtDiag(flags).toStdWString(); return 0; diff --git a/src/qtdiag/qtdiag.cpp b/src/qtdiag/qtdiag.cpp index 4e9a25f28..310cbea08 100644 --- a/src/qtdiag/qtdiag.cpp +++ b/src/qtdiag/qtdiag.cpp @@ -113,6 +113,16 @@ QTextStream &operator<<(QTextStream &str, const QFont &f) return str; } +QTextStream &operator<<(QTextStream &str, QPlatformScreen::SubpixelAntialiasingType st) +{ + static const char *enumValues[] = { + "Subpixel_None", "Subpixel_RGB", "Subpixel_BGR", "Subpixel_VRGB", "Subpixel_VBGR" + }; + str << (size_t(st) < sizeof(enumValues) / sizeof(enumValues[0]) + ? enumValues[st] : "<Unknown>"); + return str; +} + #ifndef QT_NO_OPENGL QTextStream &operator<<(QTextStream &str, const QSurfaceFormat &format) @@ -222,6 +232,18 @@ static QString formatQDebug(T t) return result; } +// Helper to format a type via QDebug, stripping the class name. +template <class T> +static QString formatValueQDebug(T t) +{ + QString result = formatQDebug(t).trimmed(); + if (result.endsWith(QLatin1Char(')'))) { + result.chop(1); + result.remove(0, result.indexOf(QLatin1Char('(')) + 1); + } + return result; +} + static inline QByteArrayList qtFeatures() { QByteArrayList result; @@ -445,11 +467,7 @@ QString qtDiag(unsigned flags) << " from " << platformTheme->themeHint(QPlatformTheme::IconThemeSearchPaths).toStringList() << '\n'; } if (const QFont *systemFont = platformTheme->font()) - str << " System font : " << *systemFont<< '\n'; - str << " General font : " << QFontDatabase::systemFont(QFontDatabase::GeneralFont) << '\n' - << " Fixed font : " << QFontDatabase::systemFont(QFontDatabase::FixedFont) << '\n' - << " Title font : " << QFontDatabase::systemFont(QFontDatabase::TitleFont) << '\n' - << " Smallest font: " << QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont) << '\n'; + str << "\n System font : " << *systemFont<< '\n'; if (platformTheme->usePlatformNativeDialog(QPlatformTheme::FileDialog)) str << " Native file dialog\n"; @@ -460,6 +478,27 @@ QString qtDiag(unsigned flags) if (platformTheme->usePlatformNativeDialog(QPlatformTheme::MessageDialog)) str << " Native message dialog\n"; + str << "\nFonts:\n General font : " << QFontDatabase::systemFont(QFontDatabase::GeneralFont) << '\n' + << " Fixed font : " << QFontDatabase::systemFont(QFontDatabase::FixedFont) << '\n' + << " Title font : " << QFontDatabase::systemFont(QFontDatabase::TitleFont) << '\n' + << " Smallest font: " << QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont) << '\n'; + if (flags & QtDiagFonts) { + QFontDatabase fontDatabase; + const QStringList families = fontDatabase.families(); + str << "\n Families (" << families.size() << "):\n"; + for (int i = 0, count = families.size(); i < count; ++i) + str << " " << families.at(i) << '\n'; + + const QList<int> standardSizes = QFontDatabase::standardSizes(); + str << "\n Standard Sizes:"; + for (int i = 0, count = standardSizes.size(); i < count; ++i) + str << ' ' << standardSizes.at(i); + QList<QFontDatabase::WritingSystem> writingSystems = fontDatabase.writingSystems(); + str << "\n\n Writing systems:\n"; + for (int i = 0, count = writingSystems.size(); i < count; ++i) + str << " " << formatValueQDebug(writingSystems.at(i)) << '\n'; + } + const QList<QScreen*> screens = QGuiApplication::screens(); const int screenCount = screens.size(); str << "\nScreens: " << screenCount << ", High DPI scaling: " @@ -490,7 +529,7 @@ QString qtDiag(unsigned flags) << " Logical DPI: " << dpi; if (dpi != nativeDpi) str << " (native: " << nativeDpi << ')'; - str << "\n "; + str << ' ' << platformScreen->subpixelAntialiasingTypeHint() << "\n "; if (QHighDpiScaling::isActive()) str << "High DPI scaling factor: " << QHighDpiScaling::factor(screen) << ' '; str << "DevicePixelRatio: " << screen->devicePixelRatio() diff --git a/src/qtdiag/qtdiag.h b/src/qtdiag/qtdiag.h index 9076c9b7e..3729a53a4 100644 --- a/src/qtdiag/qtdiag.h +++ b/src/qtdiag/qtdiag.h @@ -40,7 +40,8 @@ QT_BEGIN_NAMESPACE enum QtDiagFlags { QtDiagGl = 0x1, - QtDiagGlExtensions = 0x2 + QtDiagGlExtensions = 0x2, + QtDiagFonts = 0x4 }; QString qtDiag(unsigned flags = 0); diff --git a/src/windeployqt/main.cpp b/src/windeployqt/main.cpp index 45fd4b907..fb45a64e1 100644 --- a/src/windeployqt/main.cpp +++ b/src/windeployqt/main.cpp @@ -1474,7 +1474,8 @@ static bool deployWebEngineCore(const QMap<QString, QString> &qmakeVariables, "qtwebengine_resources_100p.pak", "qtwebengine_resources_200p.pak"}; - std::wcout << "Deploying: " << webEngineProcessC << "...\n"; + if (optVerboseLevel) + std::wcout << "Deploying: " << webEngineProcessC << "...\n"; if (!deployWebProcess(qmakeVariables, webEngineProcessC, options, errorMessage)) return false; const QString resourcesSubDir = QStringLiteral("/resources"); diff --git a/src/windeployqt/utils.cpp b/src/windeployqt/utils.cpp index 64f39619d..a29b38bbd 100644 --- a/src/windeployqt/utils.cpp +++ b/src/windeployqt/utils.cpp @@ -45,7 +45,7 @@ #include <QtCore/QStandardPaths> #if defined(Q_OS_WIN) # include <QtCore/qt_windows.h> -# include <Shlwapi.h> +# include <shlwapi.h> # include <delayimp.h> #else // Q_OS_WIN # include <sys/wait.h> diff --git a/src/windeployqt/windeployqt.pro b/src/windeployqt/windeployqt.pro index ef5534a67..4ea703948 100644 --- a/src/windeployqt/windeployqt.pro +++ b/src/windeployqt/windeployqt.pro @@ -7,6 +7,6 @@ HEADERS += utils.h qmlutils.h elfreader.h CONFIG += force_bootstrap -win32: LIBS += -lShlwapi +win32: LIBS += -lshlwapi load(qt_tool) diff --git a/src/winrtrunner/appxengine.cpp b/src/winrtrunner/appxengine.cpp index eacf52db9..c74f7c4b4 100644 --- a/src/winrtrunner/appxengine.cpp +++ b/src/winrtrunner/appxengine.cpp @@ -52,6 +52,9 @@ #include <wrl.h> #include <windows.applicationmodel.h> #include <windows.management.deployment.h> +#if _MSC_VER >= 1900 +#include <wincrypt.h> +#endif using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -62,6 +65,240 @@ using namespace ABI::Windows::System; QT_USE_NAMESPACE +#if _MSC_VER >= 1900 +// *********** Taken from MSDN Example code +// https://msdn.microsoft.com/en-us/library/windows/desktop/jj835834%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 + +#define SIGNER_SUBJECT_FILE 0x01 +#define SIGNER_NO_ATTR 0x00 +#define SIGNER_CERT_POLICY_CHAIN_NO_ROOT 0x08 +#define SIGNER_CERT_STORE 0x02 + +typedef struct _SIGNER_FILE_INFO +{ + DWORD cbSize; + LPCWSTR pwszFileName; + HANDLE hFile; +} SIGNER_FILE_INFO; + +typedef struct _SIGNER_BLOB_INFO +{ + DWORD cbSize; + GUID *pGuidSubject; + DWORD cbBlob; + BYTE *pbBlob; + LPCWSTR pwszDisplayName; +} SIGNER_BLOB_INFO; + +typedef struct _SIGNER_SUBJECT_INFO +{ + DWORD cbSize; + DWORD *pdwIndex; + DWORD dwSubjectChoice; + union + { + SIGNER_FILE_INFO *pSignerFileInfo; + SIGNER_BLOB_INFO *pSignerBlobInfo; + }; +} SIGNER_SUBJECT_INFO, *PSIGNER_SUBJECT_INFO; + +typedef struct _SIGNER_ATTR_AUTHCODE +{ + DWORD cbSize; + BOOL fCommercial; + BOOL fIndividual; + LPCWSTR pwszName; + LPCWSTR pwszInfo; +} SIGNER_ATTR_AUTHCODE; + +typedef struct _SIGNER_SIGNATURE_INFO +{ + DWORD cbSize; + ALG_ID algidHash; + DWORD dwAttrChoice; + union + { + SIGNER_ATTR_AUTHCODE *pAttrAuthcode; + }; + PCRYPT_ATTRIBUTES psAuthenticated; + PCRYPT_ATTRIBUTES psUnauthenticated; +} SIGNER_SIGNATURE_INFO, *PSIGNER_SIGNATURE_INFO; + +typedef struct _SIGNER_PROVIDER_INFO +{ + DWORD cbSize; + LPCWSTR pwszProviderName; + DWORD dwProviderType; + DWORD dwKeySpec; + DWORD dwPvkChoice; + union + { + LPWSTR pwszPvkFileName; + LPWSTR pwszKeyContainer; + }; +} SIGNER_PROVIDER_INFO, *PSIGNER_PROVIDER_INFO; + +typedef struct _SIGNER_SPC_CHAIN_INFO +{ + DWORD cbSize; + LPCWSTR pwszSpcFile; + DWORD dwCertPolicy; + HCERTSTORE hCertStore; +} SIGNER_SPC_CHAIN_INFO; + +typedef struct _SIGNER_CERT_STORE_INFO +{ + DWORD cbSize; + PCCERT_CONTEXT pSigningCert; + DWORD dwCertPolicy; + HCERTSTORE hCertStore; +} SIGNER_CERT_STORE_INFO; + +typedef struct _SIGNER_CERT +{ + DWORD cbSize; + DWORD dwCertChoice; + union + { + LPCWSTR pwszSpcFile; + SIGNER_CERT_STORE_INFO *pCertStoreInfo; + SIGNER_SPC_CHAIN_INFO *pSpcChainInfo; + }; + HWND hwnd; +} SIGNER_CERT, *PSIGNER_CERT; + +typedef struct _SIGNER_CONTEXT +{ + DWORD cbSize; + DWORD cbBlob; + BYTE *pbBlob; +} SIGNER_CONTEXT, *PSIGNER_CONTEXT; + +typedef struct _SIGNER_SIGN_EX2_PARAMS +{ + DWORD dwFlags; + PSIGNER_SUBJECT_INFO pSubjectInfo; + PSIGNER_CERT pSigningCert; + PSIGNER_SIGNATURE_INFO pSignatureInfo; + PSIGNER_PROVIDER_INFO pProviderInfo; + DWORD dwTimestampFlags; + PCSTR pszAlgorithmOid; + PCWSTR pwszTimestampURL; + PCRYPT_ATTRIBUTES pCryptAttrs; + PVOID pSipData; + PSIGNER_CONTEXT *pSignerContext; + PVOID pCryptoPolicy; + PVOID pReserved; +} SIGNER_SIGN_EX2_PARAMS, *PSIGNER_SIGN_EX2_PARAMS; + +typedef struct _APPX_SIP_CLIENT_DATA +{ + PSIGNER_SIGN_EX2_PARAMS pSignerParams; + IUnknown* pAppxSipState; +} APPX_SIP_CLIENT_DATA, *PAPPX_SIP_CLIENT_DATA; + +bool signAppxPackage(PCCERT_CONTEXT signingCertContext, LPCWSTR packageFilePath) +{ + HRESULT hr = S_OK; + + DWORD signerIndex = 0; + + SIGNER_FILE_INFO fileInfo = {}; + fileInfo.cbSize = sizeof(SIGNER_FILE_INFO); + fileInfo.pwszFileName = packageFilePath; + + SIGNER_SUBJECT_INFO subjectInfo = {}; + subjectInfo.cbSize = sizeof(SIGNER_SUBJECT_INFO); + subjectInfo.pdwIndex = &signerIndex; + subjectInfo.dwSubjectChoice = SIGNER_SUBJECT_FILE; + subjectInfo.pSignerFileInfo = &fileInfo; + + SIGNER_CERT_STORE_INFO certStoreInfo = {}; + certStoreInfo.cbSize = sizeof(SIGNER_CERT_STORE_INFO); + certStoreInfo.dwCertPolicy = SIGNER_CERT_POLICY_CHAIN_NO_ROOT; + certStoreInfo.pSigningCert = signingCertContext; + + SIGNER_CERT cert = {}; + cert.cbSize = sizeof(SIGNER_CERT); + cert.dwCertChoice = SIGNER_CERT_STORE; + cert.pCertStoreInfo = &certStoreInfo; + + // The algidHash of the signature to be created must match the + // hash algorithm used to create the app package + SIGNER_SIGNATURE_INFO signatureInfo = {}; + signatureInfo.cbSize = sizeof(SIGNER_SIGNATURE_INFO); + signatureInfo.algidHash = CALG_SHA_512; + signatureInfo.dwAttrChoice = SIGNER_NO_ATTR; + + SIGNER_SIGN_EX2_PARAMS signerParams = {}; + signerParams.pSubjectInfo = &subjectInfo; + signerParams.pSigningCert = &cert; + signerParams.pSignatureInfo = &signatureInfo; + + APPX_SIP_CLIENT_DATA sipClientData = {}; + sipClientData.pSignerParams = &signerParams; + signerParams.pSipData = &sipClientData; + + // Type definition for invoking SignerSignEx2 via GetProcAddress + typedef HRESULT (WINAPI *SignerSignEx2Function)( + DWORD, + PSIGNER_SUBJECT_INFO, + PSIGNER_CERT, + PSIGNER_SIGNATURE_INFO, + PSIGNER_PROVIDER_INFO, + DWORD, + PCSTR, + PCWSTR, + PCRYPT_ATTRIBUTES, + PVOID, + PSIGNER_CONTEXT *, + PVOID, + PVOID); + + // Load the SignerSignEx2 function from MSSign32.dll + HMODULE msSignModule = LoadLibraryEx( + L"MSSign32.dll", + NULL, + LOAD_LIBRARY_SEARCH_SYSTEM32); + + if (!msSignModule) { + qCWarning(lcWinRtRunner) << "LoadLibraryEx failed to load MSSign32.dll."; + return false; + } + + SignerSignEx2Function SignerSignEx2 = reinterpret_cast<SignerSignEx2Function>( + GetProcAddress(msSignModule, "SignerSignEx2")); + if (!SignerSignEx2) { + qCWarning(lcWinRtRunner) << "Could not resolve SignerSignEx2"; + FreeLibrary(msSignModule); + return false; + } + hr = SignerSignEx2(signerParams.dwFlags, + signerParams.pSubjectInfo, + signerParams.pSigningCert, + signerParams.pSignatureInfo, + signerParams.pProviderInfo, + signerParams.dwTimestampFlags, + signerParams.pszAlgorithmOid, + signerParams.pwszTimestampURL, + signerParams.pCryptAttrs, + signerParams.pSipData, + signerParams.pSignerContext, + signerParams.pCryptoPolicy, + signerParams.pReserved); + + FreeLibrary(msSignModule); + + RETURN_FALSE_IF_FAILED("Could not sign package."); + + if (sipClientData.pAppxSipState) + sipClientData.pAppxSipState->Release(); + + return true; +} +// ************ MSDN +#endif // MSC_VER >= 1900 + bool AppxEngine::getManifestFile(const QString &fileName, QString *manifest) { if (!QFile::exists(fileName)) { @@ -194,6 +431,14 @@ AppxEngine::AppxEngine(Runner *runner, AppxEnginePrivate *dd) d->packageFamilyName = QString::fromWCharArray(packageFamilyName); CoTaskMemFree(packageFamilyName); +#if _MSC_VER >= 1900 + LPWSTR publisher; + packageId->GetPublisher(&publisher); + CHECK_RESULT_FATAL("Failed to retrieve publisher name from package.", return); + d->publisherName = QString::fromWCharArray(publisher); + CoTaskMemFree(publisher); +#endif // _MSC_VER >= 1900 + ComPtr<IAppxManifestApplicationsEnumerator> applications; hr = manifestReader->GetApplications(&applications); CHECK_RESULT_FATAL("Failed to get a list of applications from the manifest.", return); @@ -441,3 +686,90 @@ bool AppxEngine::createPackage(const QString &packageFileName) return true; } + +bool AppxEngine::sign(const QString &fileName) +{ +#if _MSC_VER >= 1900 + Q_D(const AppxEngine); + BYTE buffer[256]; + DWORD bufferSize = 256; + + if (!CertStrToName(X509_ASN_ENCODING, wchar(d->publisherName), CERT_X500_NAME_STR, 0, buffer, &bufferSize, 0)) { + qCWarning(lcWinRtRunner) << "CertStrToName failed"; + return false; + } + CERT_NAME_BLOB certBlob; + certBlob.cbData = bufferSize; + certBlob.pbData = buffer; + + CRYPT_ALGORITHM_IDENTIFIER identifier; + identifier.pszObjId = strdup(szOID_RSA_SHA256RSA); + identifier.Parameters.cbData = 0; + identifier.Parameters.pbData = NULL; + + CERT_EXTENSIONS extensions; + extensions.cExtension = 2; + extensions.rgExtension = new CERT_EXTENSION[2]; + + // Basic Constraints + CERT_BASIC_CONSTRAINTS2_INFO constraintsInfo; + constraintsInfo.fCA = FALSE; + constraintsInfo.fPathLenConstraint = FALSE; + constraintsInfo.dwPathLenConstraint = 0; + + BYTE *constraintsEncoded = NULL; + DWORD encodedSize = 0; + CryptEncodeObject(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &constraintsInfo, + constraintsEncoded, &encodedSize); + constraintsEncoded = new BYTE[encodedSize]; + if (!CryptEncodeObject(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &constraintsInfo, + constraintsEncoded, &encodedSize)) { + qCWarning(lcWinRtRunner) << "Could not encode basic constraints."; + delete [] constraintsEncoded; + return false; + } + + extensions.rgExtension[0].pszObjId = strdup(szOID_BASIC_CONSTRAINTS2); + extensions.rgExtension[0].fCritical = TRUE; + extensions.rgExtension[0].Value.cbData = encodedSize; + extensions.rgExtension[0].Value.pbData = constraintsEncoded; + + // Code Signing + char *codeSign = strdup(szOID_PKIX_KP_CODE_SIGNING); + CERT_ENHKEY_USAGE enhancedUsage; + enhancedUsage.cUsageIdentifier = 1; + enhancedUsage.rgpszUsageIdentifier = &codeSign; + + BYTE *enhancedKeyEncoded = 0; + encodedSize = 0; + CryptEncodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &enhancedUsage, + enhancedKeyEncoded, &encodedSize); + enhancedKeyEncoded = new BYTE[encodedSize]; + if (!CryptEncodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &enhancedUsage, + enhancedKeyEncoded, &encodedSize)) { + qCWarning(lcWinRtRunner) << "Could not encode enhanced key usage."; + delete [] constraintsEncoded; + return false; + } + + extensions.rgExtension[1].pszObjId = strdup(szOID_ENHANCED_KEY_USAGE); + extensions.rgExtension[1].fCritical = TRUE; + extensions.rgExtension[1].Value.cbData = encodedSize; + extensions.rgExtension[1].Value.pbData = enhancedKeyEncoded; + + PCCERT_CONTEXT context = CertCreateSelfSignCertificate(NULL, &certBlob, NULL, NULL, + &identifier, NULL, NULL, &extensions); + + delete [] constraintsEncoded; + + if (!context) { + qCWarning(lcWinRtRunner) << "Failed to create self sign certificate:" << GetLastError(); + return false; + } + + return signAppxPackage(context, wchar(fileName)); +#else // _MSC_VER < 1900 + Q_UNUSED(fileName); + return true; +#endif // _MSC_VER < 1900 +} diff --git a/src/winrtrunner/appxengine.h b/src/winrtrunner/appxengine.h index 30b03fe07..4aec67588 100644 --- a/src/winrtrunner/appxengine.h +++ b/src/winrtrunner/appxengine.h @@ -63,6 +63,7 @@ protected: bool installDependencies(); bool createPackage(const QString &packageFileName); + bool sign(const QString &fileName); static bool getManifestFile(const QString &fileName, QString *manifest = 0); QScopedPointer<AppxEnginePrivate> d_ptr; diff --git a/src/winrtrunner/appxengine_p.h b/src/winrtrunner/appxengine_p.h index 4d20acf91..982c484b2 100644 --- a/src/winrtrunner/appxengine_p.h +++ b/src/winrtrunner/appxengine_p.h @@ -73,6 +73,7 @@ public: QString manifest; QString packageFullName; QString packageFamilyName; + QString publisherName; ABI::Windows::System::ProcessorArchitecture packageArchitecture; QString executable; qint64 pid; diff --git a/src/winrtrunner/appxphoneengine.cpp b/src/winrtrunner/appxphoneengine.cpp index e7cbf6709..edbb58ea5 100644 --- a/src/winrtrunner/appxphoneengine.cpp +++ b/src/winrtrunner/appxphoneengine.cpp @@ -258,6 +258,14 @@ AppxPhoneEngine::~AppxPhoneEngine() QString AppxPhoneEngine::extensionSdkPath() const { +#if _MSC_VER >= 1900 + const QByteArray extensionSdkDirRaw = qgetenv("ExtensionSdkDir"); + if (extensionSdkDirRaw.isEmpty()) { + qCWarning(lcWinRtRunner) << "The environment variable ExtensionSdkDir is not set."; + return QString(); + } + return QString::fromLocal8Bit(extensionSdkDirRaw); +#else // _MSC_VER < 1900 HKEY regKey; LONG hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, @@ -278,6 +286,7 @@ QString AppxPhoneEngine::extensionSdkPath() const return QString::fromWCharArray(pathData, (pathLength - 1) / sizeof(wchar_t)) + QLatin1String("ExtensionSDKs"); +#endif // _MSC_VER < 1900 } bool AppxPhoneEngine::installPackage(IAppxManifestReader *reader, const QString &filePath) @@ -384,6 +393,9 @@ bool AppxPhoneEngine::install(bool removeFirst) if (!createPackage(packageFileName)) return false; + if (!sign(packageFileName)) + return false; + ComPtr<IStream> manifestStream; hr = SHCreateStreamOnFile(wchar(d->manifest), STGM_READ, &manifestStream); RETURN_FALSE_IF_FAILED("Failed to open manifest stream"); diff --git a/src/winrtrunner/winrtrunner.pro b/src/winrtrunner/winrtrunner.pro index c98f0df70..73ca2cdd4 100644 --- a/src/winrtrunner/winrtrunner.pro +++ b/src/winrtrunner/winrtrunner.pro @@ -17,4 +17,7 @@ win32-msvc2013|win32-msvc2015 { include(../shared/corecon/corecon.pri) } +# Windows 10 requires signing +*msvc2015: LIBS += -lcrypt32 + load(qt_tool) diff --git a/tests/auto/linguist/lupdate/testdata/good/parsecpp/main.cpp b/tests/auto/linguist/lupdate/testdata/good/parsecpp/main.cpp index f4ac1e214..d58ddf9fb 100644 --- a/tests/auto/linguist/lupdate/testdata/good/parsecpp/main.cpp +++ b/tests/auto/linguist/lupdate/testdata/good/parsecpp/main.cpp @@ -488,3 +488,22 @@ class TernaryClass : public QObject tr("ternary, ddd, false"); } }; + + + +// QTBUG-47467: lupdate confused by nullptr in case of plural forms +void nullptrInPlural() +{ + QObject::tr("%n nullptr(s)", nullptr, 3); + QCoreApplication::translate("Plurals, nullptr", "%n car(s)", nullptr, QCoreApplication::UnicodeUTF8, 1); +} + +class nullptrClass : public QObject +{ + Q_OBJECT + + void f() + { + tr("%n car(s)", nullptr, 2); + } +}; diff --git a/tests/auto/linguist/lupdate/testdata/good/parsecpp/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parsecpp/project.ts.result index b847f8f89..be9df15ca 100644 --- a/tests/auto/linguist/lupdate/testdata/good/parsecpp/project.ts.result +++ b/tests/auto/linguist/lupdate/testdata/good/parsecpp/project.ts.result @@ -235,6 +235,16 @@ backslashed \ stuff.</source> </message> </context> <context> + <name>Plurals, nullptr</name> + <message numerus="yes"> + <location filename="main.cpp" line="498"/> + <source>%n car(s)</source> + <translation type="unfinished"> + <numerusform></numerusform> + </translation> + </message> +</context> +<context> <name>QApplication</name> <message> <location filename="main.cpp" line="43"/> @@ -302,6 +312,13 @@ backslashed \ stuff.</source> <extracomment>comment, bbb, false</extracomment> <translation type="unfinished"></translation> </message> + <message numerus="yes"> + <location filename="main.cpp" line="497"/> + <source>%n nullptr(s)</source> + <translation type="unfinished"> + <numerusform></numerusform> + </translation> + </message> <message> <location filename="included.cpp" line="34"/> <source>message from #included .cpp file</source> @@ -456,6 +473,16 @@ backslashed \ stuff.</source> </message> </context> <context> + <name>nullptrClass</name> + <message numerus="yes"> + <location filename="main.cpp" line="507"/> + <source>%n car(s)</source> + <translation type="unfinished"> + <numerusform></numerusform> + </translation> + </message> +</context> +<context> <name>scope</name> <message numerus="yes"> <location filename="main.cpp" line="179"/> diff --git a/tests/manual/uiloader/uiloader/tst_uiloader.cpp b/tests/manual/uiloader/uiloader/tst_uiloader.cpp index cf6e3851b..a0fda4cef 100644 --- a/tests/manual/uiloader/uiloader/tst_uiloader.cpp +++ b/tests/manual/uiloader/uiloader/tst_uiloader.cpp @@ -38,10 +38,6 @@ #include <QApplication> #include <QDir> -#ifdef Q_OS_SYMBIAN -#define SRCDIR "" -#endif - class uiLoaderAutotest: public QObject { |