diff options
author | Orgad Shaneh <orgad.shaneh@audiocodes.com> | 2016-08-05 11:59:28 +0300 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2016-08-05 11:40:07 +0200 |
commit | 1853f01a5b0955a28e9c321cd36f45d5f17651bf (patch) | |
tree | 5d357de37f3c2ef93e38bbc79ef96b6f8982cd6f /src | |
parent | 713bc04ad4560123d97bb469d109a0885cf36373 (diff) | |
parent | d004203b13fa17d1258ee62d5eb4f681adf32398 (diff) |
Merge remote-tracking branch 'origin/4.1'
Change-Id: Ia442f30f387fe9292217582260bbe79e54608810
Diffstat (limited to 'src')
55 files changed, 1043 insertions, 1220 deletions
diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp index 63d9840853..cf8fd1b85e 100644 --- a/src/libs/extensionsystem/pluginmanager.cpp +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -51,6 +51,7 @@ #include <utils/qtcassert.h> #ifdef WITH_TESTS +#include <utils/hostosinfo.h> #include <QTest> #endif @@ -1025,7 +1026,8 @@ static int executeTestPlan(const TestPlan &testPlan) << QLatin1String("-maxwarnings") << QLatin1String("0"); // unlimit output qExecArguments << functions; // avoid being stuck in QTBUG-24925 - qExecArguments << "-nocrashhandler"; + if (!Utils::HostOsInfo::isWindowsHost()) + qExecArguments << "-nocrashhandler"; failedTests += QTest::qExec(testObject, qExecArguments); } diff --git a/src/libs/utils/smallstring.h b/src/libs/utils/smallstring.h index 9e7ad9fb69..316fdb7741 100644 --- a/src/libs/utils/smallstring.h +++ b/src/libs/utils/smallstring.h @@ -38,6 +38,7 @@ #include <QString> #include <algorithm> +#include <cmath> #include <cstdlib> #include <climits> #include <cstring> diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index dd2eac9a0d..188ed0cc9e 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -282,6 +282,7 @@ public: ClangCodeModel_Warning_TextMarkColor, /* QmlDesigner */ + QmlDesigner_BackgroundColor, QmlDesigner_HighlightColor }; diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 62361a443c..a56ec7ffd5 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -258,23 +258,6 @@ static int extractPid(const QString &exeName, const QByteArray &psOutput) return extractPidFromChunk(psOutput, from); } -QByteArray AndroidRunner::runPs() -{ - if (QThread::currentThread() != thread()) { - QByteArray ret; - QMetaObject::invokeMethod(this, "runPs", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QByteArray, ret)); - return ret; - } else { - QByteArray psLine("ps"); - if (m_isBusyBox) - psLine += " -w"; - psLine += '\n'; - m_psProc.write(psLine); - m_psProc.waitForBytesWritten(psLine.size()); - return m_psProc.readAllStandardOutput(); - } -} - void AndroidRunner::launchAVDProcesses() { // Its assumed that the device or avd serial returned by selector() is online. @@ -284,8 +267,13 @@ void AndroidRunner::launchAVDProcesses() void AndroidRunner::checkPID() { - QByteArray psOut = runPs(); - m_processPID = extractPid(m_androidRunnable.packageName, psOut); + // Don't write to m_psProc from a different thread + QTC_ASSERT(QThread::currentThread() == thread(), return); + + QByteArray psLine(m_isBusyBox ? "ps -w\n" : "ps\n"); + m_psProc.write(psLine); + m_psProc.waitForBytesWritten(psLine.size()); + m_processPID = extractPid(m_androidRunnable.packageName, m_psProc.readAllStandardOutput()); if (m_processPID == -1) { if (m_wasStarted) { @@ -320,11 +308,17 @@ void AndroidRunner::checkPID() void AndroidRunner::forceStop() { + // Don't run Utils::SynchronousProcess on the GUI thread + QTC_ASSERT(QThread::currentThread() != thread(), return); + runAdb(selector() << _("shell") << _("am") << _("force-stop") << m_androidRunnable.packageName, nullptr, 30); // try killing it via kill -9 - const QByteArray out = runPs(); + const QByteArray out = Utils::SynchronousProcess() + .runBlocking(m_adb, selector() << _("shell") << _(m_isBusyBox ? "ps -w" : "ps")) + .allRawOutput(); + int from = 0; while (1) { const int to = out.indexOf('\n', from); @@ -346,7 +340,7 @@ void AndroidRunner::start() launchAVD(); } - Utils::runAsync(&AndroidRunner::asyncStart, this); + Utils::runAsync(&AndroidRunner::asyncStart, this).waitForFinished(); } void AndroidRunner::asyncStart() @@ -588,8 +582,6 @@ void AndroidRunner::handleRemoteDebuggerRunning() void AndroidRunner::stop() { - QMutexLocker locker(&m_mutex); - if (m_avdFutureInterface.isRunning()) { m_avdFutureInterface.cancel(); m_avdFutureInterface.waitForFinished(); @@ -597,16 +589,21 @@ void AndroidRunner::stop() } m_checkPIDTimer.stop(); + m_adbLogcatProcess.kill(); + m_psProc.kill(); + Utils::runAsync(&AndroidRunner::asyncStop, this).waitForFinished(); + m_adbLogcatProcess.waitForFinished(); + m_psProc.waitForFinished(); +} + +void AndroidRunner::asyncStop() +{ + QMutexLocker locker(&m_mutex); m_tries = 0; if (m_processPID != -1) { forceStop(); emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" terminated.").arg(m_androidRunnable.packageName)); } - //QObject::disconnect(&m_adbLogcatProcess, 0, this, 0); - m_adbLogcatProcess.kill(); - m_adbLogcatProcess.waitForFinished(); - m_psProc.kill(); - m_psProc.waitForFinished(); foreach (const QStringList &entry, m_androidRunnable.afterFinishADBCommands) runAdb(selector() << entry); } diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 3ed99e0061..62e7ad9518 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -80,7 +80,7 @@ private: void logcatReadStandardError(); void logcatReadStandardOutput(); void asyncStart(); - Q_INVOKABLE QByteArray runPs(); + void asyncStop(); Q_INVOKABLE void launchAVDProcesses(); void adbKill(qint64 pid); QStringList selector() const { return m_selector; } diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index 45f7a07b1b..ff911de5d3 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -318,8 +318,13 @@ void TestCodeParser::scanForTests(const QStringList &fileList) QStringList list; if (isFullParse) { list = ProjectExplorer::SessionManager::startupProject()->files(ProjectExplorer::Project::SourceFiles); - if (list.isEmpty()) + if (list.isEmpty()) { + // at least project file should be there, but might happen if parsing current project + // takes too long, especially when opening sessions holding multiple projects + qCDebug(LOG) << "File list empty (FullParse) - trying again in a sec"; + emitUpdateTestTree(); return; + } qCDebug(LOG) << "setting state to FullParse (scanForTests)"; m_parserState = FullParse; } else { diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.ui b/src/plugins/coreplugin/dialogs/externaltoolconfig.ui index 1c8a76c30e..36d3247d26 100644 --- a/src/plugins/coreplugin/dialogs/externaltoolconfig.ui +++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.ui @@ -288,6 +288,19 @@ </slots> </customwidget> </customwidgets> + <tabstops> + <tabstop>toolTree</tabstop> + <tabstop>addButton</tabstop> + <tabstop>removeButton</tabstop> + <tabstop>revertButton</tabstop> + <tabstop>description</tabstop> + <tabstop>arguments</tabstop> + <tabstop>outputBehavior</tabstop> + <tabstop>errorOutputBehavior</tabstop> + <tabstop>environmentButton</tabstop> + <tabstop>modifiesDocumentCheckbox</tabstop> + <tabstop>inputText</tabstop> + </tabstops> <resources/> <connections/> </ui> diff --git a/src/plugins/coreplugin/find/itemviewfind.cpp b/src/plugins/coreplugin/find/itemviewfind.cpp index b9328f6550..3588f125ec 100644 --- a/src/plugins/coreplugin/find/itemviewfind.cpp +++ b/src/plugins/coreplugin/find/itemviewfind.cpp @@ -128,25 +128,42 @@ IFindSupport::Result ItemViewFind::findStep(const QString &txt, FindFlags findFl return result; } -QFrame *ItemViewFind::createSearchableWrapper(QAbstractItemView *treeView, ColorOption lightColored, FetchOption option) +static QFrame *createHelper(QAbstractItemView *treeView, + ItemViewFind::ColorOption colorOption, + ItemViewFind *finder) { - QFrame *widget = new QFrame; + auto widget = new QFrame; widget->setFrameStyle(QFrame::NoFrame); - QVBoxLayout *vbox = new QVBoxLayout(widget); + + auto placeHolder = new FindToolBarPlaceHolder(widget); + placeHolder->setLightColored(colorOption); + + auto vbox = new QVBoxLayout(widget); vbox->setMargin(0); vbox->setSpacing(0); vbox->addWidget(treeView); - auto placeHolder = new FindToolBarPlaceHolder(widget); - placeHolder->setLightColored(lightColored); vbox->addWidget(placeHolder); - Aggregation::Aggregate *agg = new Aggregation::Aggregate; + auto agg = new Aggregation::Aggregate; agg->add(treeView); - agg->add(new ItemViewFind(treeView, Qt::DisplayRole, option)); + agg->add(finder); return widget; } +QFrame *ItemViewFind::createSearchableWrapper(QAbstractItemView *treeView, + ColorOption colorOption, + FetchOption option) +{ + return createHelper(treeView, colorOption, new ItemViewFind(treeView, Qt::DisplayRole, option)); +} + +QFrame *ItemViewFind::createSearchableWrapper(ItemViewFind *finder, + ItemViewFind::ColorOption colorOption) +{ + return createHelper(finder->d->m_view, colorOption, finder); +} + IFindSupport::Result ItemViewFind::find(const QString &searchTxt, FindFlags findFlags, bool startFromCurrentIndex, diff --git a/src/plugins/coreplugin/find/itemviewfind.h b/src/plugins/coreplugin/find/itemviewfind.h index dad9089dc5..026ed4d557 100644 --- a/src/plugins/coreplugin/find/itemviewfind.h +++ b/src/plugins/coreplugin/find/itemviewfind.h @@ -65,8 +65,10 @@ public: Result findIncremental(const QString &txt, FindFlags findFlags); Result findStep(const QString &txt, FindFlags findFlags); - static QFrame *createSearchableWrapper(QAbstractItemView *treeView, ColorOption lightColored = DarkColored, + static QFrame *createSearchableWrapper(QAbstractItemView *treeView, ColorOption colorOption = DarkColored, FetchOption option = DoNotFetchMoreWhileSearching); + static QFrame *createSearchableWrapper(ItemViewFind *finder, ColorOption colorOption = DarkColored); + private: Result find(const QString &txt, FindFlags findFlags, bool startFromCurrentIndex, bool *wrapped); diff --git a/src/plugins/coreplugin/generalsettings.ui b/src/plugins/coreplugin/generalsettings.ui index be3adc7c55..333be51ac7 100644 --- a/src/plugins/coreplugin/generalsettings.ui +++ b/src/plugins/coreplugin/generalsettings.ui @@ -155,6 +155,12 @@ <container>1</container> </customwidget> </customwidgets> + <tabstops> + <tabstop>colorButton</tabstop> + <tabstop>resetColorButton</tabstop> + <tabstop>languageBox</tabstop> + <tabstop>resetWarningsButton</tabstop> + </tabstops> <resources/> <connections/> </ui> diff --git a/src/plugins/coreplugin/mimetypemagicdialog.ui b/src/plugins/coreplugin/mimetypemagicdialog.ui index bca3dad241..f638354881 100644 --- a/src/plugins/coreplugin/mimetypemagicdialog.ui +++ b/src/plugins/coreplugin/mimetypemagicdialog.ui @@ -238,6 +238,15 @@ </item> </layout> </widget> + <tabstops> + <tabstop>valueLineEdit</tabstop> + <tabstop>typeSelector</tabstop> + <tabstop>maskLineEdit</tabstop> + <tabstop>useRecommendedGroupBox</tabstop> + <tabstop>startRangeSpinBox</tabstop> + <tabstop>endRangeSpinBox</tabstop> + <tabstop>prioritySpinBox</tabstop> + </tabstops> <resources/> <connections> <connection> diff --git a/src/plugins/coreplugin/mimetypesettingspage.ui b/src/plugins/coreplugin/mimetypesettingspage.ui index 2b4e6fbadc..ca3a23f8a2 100644 --- a/src/plugins/coreplugin/mimetypesettingspage.ui +++ b/src/plugins/coreplugin/mimetypesettingspage.ui @@ -169,6 +169,16 @@ </item> </layout> </widget> + <tabstops> + <tabstop>filterLineEdit</tabstop> + <tabstop>mimeTypesTreeView</tabstop> + <tabstop>resetButton</tabstop> + <tabstop>patternsLineEdit</tabstop> + <tabstop>magicHeadersTreeWidget</tabstop> + <tabstop>addMagicButton</tabstop> + <tabstop>editMagicButton</tabstop> + <tabstop>removeMagicButton</tabstop> + </tabstops> <resources/> <connections/> </ui> diff --git a/src/plugins/coreplugin/systemsettings.ui b/src/plugins/coreplugin/systemsettings.ui index f79d829a47..0afda779ea 100644 --- a/src/plugins/coreplugin/systemsettings.ui +++ b/src/plugins/coreplugin/systemsettings.ui @@ -374,6 +374,21 @@ </slots> </customwidget> </customwidgets> + <tabstops> + <tabstop>terminalComboBox</tabstop> + <tabstop>resetTerminalButton</tabstop> + <tabstop>externalFileBrowserEdit</tabstop> + <tabstop>resetFileBrowserButton</tabstop> + <tabstop>helpExternalFileBrowserButton</tabstop> + <tabstop>fileSystemCaseSensitivityChooser</tabstop> + <tabstop>reloadBehavior</tabstop> + <tabstop>autoSaveCheckBox</tabstop> + <tabstop>autoSaveInterval</tabstop> + <tabstop>autoSuspendCheckBox</tabstop> + <tabstop>autoSuspendMinDocumentCount</tabstop> + <tabstop>warnBeforeOpeningBigFiles</tabstop> + <tabstop>bigFilesLimitSpinBox</tabstop> + </tabstops> <resources> <include location="core.qrc"/> </resources> diff --git a/src/plugins/cppeditor/cppautocompleter.cpp b/src/plugins/cppeditor/cppautocompleter.cpp index 2df19e8a02..da1e6b527b 100644 --- a/src/plugins/cppeditor/cppautocompleter.cpp +++ b/src/plugins/cppeditor/cppautocompleter.cpp @@ -371,7 +371,7 @@ void CppEditorPlugin::test_autoBackspace_data() QTest::newRow((QLatin1String("Inside ") + charGroupTestName(c)).toLatin1().data()) << fileContent(InBetween, c) - << QString("([").contains(c); + << QString("(['\"").contains(c); } } diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro index b616682dce..6394bba5bb 100644 --- a/src/plugins/cppeditor/cppeditor.pro +++ b/src/plugins/cppeditor/cppeditor.pro @@ -18,9 +18,6 @@ HEADERS += \ cpphighlighter.h \ cpphoverhandler.h \ cppincludehierarchy.h \ - cppincludehierarchyitem.h \ - cppincludehierarchymodel.h \ - cppincludehierarchytreeview.h \ cppinsertvirtualmethods.h \ cpplocalrenaming.h \ cppoutline.h \ @@ -48,9 +45,6 @@ SOURCES += \ cpphighlighter.cpp \ cpphoverhandler.cpp \ cppincludehierarchy.cpp \ - cppincludehierarchyitem.cpp \ - cppincludehierarchymodel.cpp \ - cppincludehierarchytreeview.cpp \ cppinsertvirtualmethods.cpp \ cpplocalrenaming.cpp \ cppoutline.cpp \ diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index 79105dc907..8267939e14 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -37,9 +37,6 @@ QtcPlugin { "cpphighlighter.cpp", "cpphighlighter.h", "cpphoverhandler.cpp", "cpphoverhandler.h", "cppincludehierarchy.cpp", "cppincludehierarchy.h", - "cppincludehierarchyitem.cpp", "cppincludehierarchyitem.h", - "cppincludehierarchymodel.cpp", "cppincludehierarchymodel.h", - "cppincludehierarchytreeview.cpp", "cppincludehierarchytreeview.h", "cppinsertvirtualmethods.cpp", "cppinsertvirtualmethods.h", "cpplocalrenaming.cpp", "cpplocalrenaming.h", diff --git a/src/plugins/cppeditor/cppincludehierarchy.cpp b/src/plugins/cppeditor/cppincludehierarchy.cpp index b2eedf8021..b3b4f6c9f9 100644 --- a/src/plugins/cppeditor/cppincludehierarchy.cpp +++ b/src/plugins/cppeditor/cppincludehierarchy.cpp @@ -29,50 +29,341 @@ #include "cppeditorconstants.h" #include "cppeditorplugin.h" #include "cppelementevaluator.h" -#include "cppincludehierarchymodel.h" -#include "cppincludehierarchytreeview.h" - -#include <texteditor/textdocument.h> #include <coreplugin/editormanager/editormanager.h> +#include <coreplugin/fileiconprovider.h> #include <coreplugin/find/itemviewfind.h> + +#include <cpptools/baseeditordocumentprocessor.h> +#include <cpptools/cppmodelmanager.h> +#include <cpptools/cpptoolsbridge.h> +#include <cpptools/editordocumenthandle.h> + #include <cplusplus/CppDocument.h> #include <utils/annotateditemdelegate.h> +#include <utils/dropsupport.h> #include <utils/fileutils.h> +#include <utils/navigationtreeview.h> +#include <utils/qtcassert.h> -#include <QDir> +#include <QCoreApplication> +#include <QKeyEvent> #include <QLabel> -#include <QLatin1String> -#include <QModelIndex> -#include <QStandardItem> +#include <QStackedWidget> #include <QVBoxLayout> +using namespace Core; +using namespace CPlusPlus; +using namespace CppTools; using namespace TextEditor; using namespace Utils; namespace CppEditor { namespace Internal { +enum { + AnnotationRole = Qt::UserRole + 1, + LinkRole +}; + +static Snapshot globalSnapshot() +{ + return CppModelManager::instance()->snapshot(); +} + +struct FileAndLine +{ + FileAndLine() {} + FileAndLine(const QString &f, int l) : file(f), line(l) {} + + QString file; + int line = 0; +}; + +using FileAndLines = QList<FileAndLine>; + +static FileAndLines findIncluders(const QString &filePath) +{ + FileAndLines result; + const Snapshot snapshot = globalSnapshot(); + for (auto cit = snapshot.begin(), citEnd = snapshot.end(); cit != citEnd; ++cit) { + const QString filePathFromSnapshot = cit.key().toString(); + Document::Ptr doc = cit.value(); + const QList<Document::Include> resolvedIncludes = doc->resolvedIncludes(); + for (const auto &includeFile : resolvedIncludes) { + const QString includedFilePath = includeFile.resolvedFileName(); + if (includedFilePath == filePath) + result.append(FileAndLine(filePathFromSnapshot, int(includeFile.line()))); + } + } + return result; +} + +static FileAndLines findIncludes(const QString &filePath, const Snapshot &snapshot) +{ + FileAndLines result; + if (Document::Ptr doc = snapshot.document(filePath)) { + const QList<Document::Include> resolvedIncludes = doc->resolvedIncludes(); + for (const auto &includeFile : resolvedIncludes) + result.append(FileAndLine(includeFile.resolvedFileName(), 0)); + } + return result; +} + +class CppIncludeHierarchyItem + : public TypedTreeItem<CppIncludeHierarchyItem, CppIncludeHierarchyItem> +{ +public: + enum SubTree { RootItem, InIncludes, InIncludedBy }; + CppIncludeHierarchyItem() {} + + void createChild(const QString &filePath, SubTree subTree, + int line = 0, bool definitelyNoChildren = false) + { + auto item = new CppIncludeHierarchyItem; + item->m_fileName = filePath.mid(filePath.lastIndexOf('/') + 1); + item->m_filePath = filePath; + item->m_line = line; + item->m_subTree = subTree; + appendChild(item); + for (auto ancestor = this; ancestor; ancestor = ancestor->parent()) { + if (ancestor->filePath() == filePath) { + item->m_isCyclic = true; + break; + } + } + if (filePath == model()->editorFilePath() || definitelyNoChildren) + item->setChildrenChecked(); + } + + QString filePath() const + { + return isPhony() ? model()->editorFilePath() : m_filePath; + } + +private: + bool isPhony() const { return !parent() || !parent()->parent(); } + void setChildrenChecked() { m_checkedForChildren = true; } + + CppIncludeHierarchyModel *model() const + { + return static_cast<CppIncludeHierarchyModel *>(TreeItem::model()); + } + + QVariant data(int column, int role) const override; + + Qt::ItemFlags flags(int) const override + { + TextEditorWidget::Link link(m_filePath, m_line); + if (link.hasValidTarget()) + return Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsSelectable; + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } + + bool canFetchMore() const override; + void fetchMore() override; + + QString m_fileName; + QString m_filePath; + int m_line = 0; + SubTree m_subTree = RootItem; + bool m_isCyclic = false; + bool m_checkedForChildren = false; +}; + +QVariant CppIncludeHierarchyItem::data(int column, int role) const +{ + Q_UNUSED(column); + if (role == Qt::DisplayRole) { + if (isPhony() && childCount() == 0) + return QString(m_fileName + ' ' + CppIncludeHierarchyModel::tr("(none)")); + if (m_isCyclic) + return QString(m_fileName + ' ' + CppIncludeHierarchyModel::tr("(cyclic)")); + return m_fileName; + } + + if (isPhony()) + return QVariant(); + + switch (role) { + case Qt::ToolTipRole: + return m_filePath; + case Qt::DecorationRole: + return FileIconProvider::icon(QFileInfo(m_filePath)); + case LinkRole: + return QVariant::fromValue(TextEditorWidget::Link(m_filePath, m_line)); + } + + return QVariant(); +} + +bool CppIncludeHierarchyItem::canFetchMore() const +{ + if (m_isCyclic || m_checkedForChildren || !children().isEmpty()) + return false; + + return !model()->m_searching || !model()->m_seen.contains(m_filePath); +} + +void CppIncludeHierarchyItem::fetchMore() +{ + QTC_ASSERT(canFetchMore(), setChildrenChecked(); return); + QTC_ASSERT(model(), return); + QTC_ASSERT(m_subTree != RootItem, return); // Root should always be populated. + + model()->m_seen.insert(m_filePath); + + const QString editorFilePath = model()->editorFilePath(); + + setChildrenChecked(); + if (m_subTree == InIncludes) { + auto processor = CppToolsBridge::baseEditorDocumentProcessor(editorFilePath); + QTC_ASSERT(processor, return); + const Snapshot snapshot = processor->snapshot(); + const FileAndLines includes = findIncludes(filePath(), snapshot); + for (const FileAndLine &include : includes) { + const FileAndLines subIncludes = findIncludes(include.file, snapshot); + bool definitelyNoChildren = subIncludes.isEmpty(); + createChild(include.file, InIncludes, include.line, definitelyNoChildren); + } + } else if (m_subTree == InIncludedBy) { + const FileAndLines includers = findIncluders(filePath()); + for (const FileAndLine &includer : includers) { + const FileAndLines subIncluders = findIncluders(includer.file); + bool definitelyNoChildren = subIncluders.isEmpty(); + createChild(includer.file, InIncludedBy, includer.line, definitelyNoChildren); + } + } +} + +void CppIncludeHierarchyModel::buildHierarchy(const QString &document) +{ + m_editorFilePath = document; + rootItem()->removeChildren(); + rootItem()->createChild(tr("Includes"), CppIncludeHierarchyItem::InIncludes); + rootItem()->createChild(tr("Included by"), CppIncludeHierarchyItem::InIncludedBy); +} + +void CppIncludeHierarchyModel::setSearching(bool on) +{ + m_searching = on; + m_seen.clear(); +} + + +// CppIncludeHierarchyModel + +CppIncludeHierarchyModel::CppIncludeHierarchyModel() +{ + setRootItem(new CppIncludeHierarchyItem); // FIXME: Remove in 4.2 +} + +Qt::DropActions CppIncludeHierarchyModel::supportedDragActions() const +{ + return Qt::MoveAction; +} + +QStringList CppIncludeHierarchyModel::mimeTypes() const +{ + return DropSupport::mimeTypesForFilePaths(); +} + +QMimeData *CppIncludeHierarchyModel::mimeData(const QModelIndexList &indexes) const +{ + auto data = new DropMimeData; + foreach (const QModelIndex &index, indexes) { + auto link = index.data(LinkRole).value<TextEditorWidget::Link>(); + if (link.hasValidTarget()) + data->addFile(link.targetFileName, link.targetLine, link.targetColumn); + } + return data; +} + + +// CppIncludeHierarchyTreeView + +class CppIncludeHierarchyTreeView : public NavigationTreeView +{ +public: + CppIncludeHierarchyTreeView() + { + setDragEnabled(true); + setDragDropMode(QAbstractItemView::DragOnly); + } + +protected: + void keyPressEvent(QKeyEvent *event) override + { + if (event->key()) + QAbstractItemView::keyPressEvent(event); + else + NavigationTreeView::keyPressEvent(event); + } +}; + + +// IncludeFinder + +class IncludeFinder : public ItemViewFind +{ +public: + IncludeFinder(QAbstractItemView *view, CppIncludeHierarchyModel *model) + : ItemViewFind(view, Qt::DisplayRole, FetchMoreWhileSearching) + , m_model(model) + {} + +private: + Result findIncremental(const QString &txt, FindFlags findFlags) + { + m_model->setSearching(true); + Result result = ItemViewFind::findIncremental(txt, findFlags); + m_model->setSearching(false); + return result; + } + + CppIncludeHierarchyModel *m_model; // Not owned. +}; + + // CppIncludeHierarchyWidget -CppIncludeHierarchyWidget::CppIncludeHierarchyWidget() : - QWidget(0), - m_treeView(0), - m_model(0), - m_delegate(0), - m_includeHierarchyInfoLabel(0), - m_editor(0) + +class CppIncludeHierarchyWidget : public QWidget +{ + Q_DECLARE_TR_FUNCTIONS(CppEditor::CppIncludeHierarchy) + +public: + CppIncludeHierarchyWidget(); + ~CppIncludeHierarchyWidget() { delete m_treeView; } + + void perform(); + +private: + void onItemActivated(const QModelIndex &index); + void editorsClosed(QList<IEditor *> editors); + void showNoIncludeHierarchyLabel(); + void showIncludeHierarchy(); + + CppIncludeHierarchyTreeView *m_treeView = nullptr; + CppIncludeHierarchyModel m_model; + AnnotatedItemDelegate m_delegate; + TextEditorLinkLabel *m_inspectedFile = nullptr; + QLabel *m_includeHierarchyInfoLabel = nullptr; + BaseTextEditor *m_editor = nullptr; +}; + +CppIncludeHierarchyWidget::CppIncludeHierarchyWidget() { + m_delegate.setDelimiter(" "); + m_delegate.setAnnotationRole(AnnotationRole); + m_inspectedFile = new TextEditorLinkLabel(this); m_inspectedFile->setMargin(5); - m_model = new CppIncludeHierarchyModel(this); - m_treeView = new CppIncludeHierarchyTreeView(this); - m_delegate = new AnnotatedItemDelegate(this); - m_delegate->setDelimiter(QLatin1String(" ")); - m_delegate->setAnnotationRole(AnnotationRole); - m_treeView->setModel(m_model); + + m_treeView = new CppIncludeHierarchyTreeView; + m_treeView->setModel(&m_model); m_treeView->setEditTriggers(QAbstractItemView::NoEditTriggers); - m_treeView->setItemDelegate(m_delegate); + m_treeView->setItemDelegate(&m_delegate); connect(m_treeView, &QAbstractItemView::activated, this, &CppIncludeHierarchyWidget::onItemActivated); m_includeHierarchyInfoLabel = new QLabel(tr("No include hierarchy available"), this); @@ -81,69 +372,53 @@ CppIncludeHierarchyWidget::CppIncludeHierarchyWidget() : m_includeHierarchyInfoLabel->setBackgroundRole(QPalette::Base); m_includeHierarchyInfoLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); - QVBoxLayout *layout = new QVBoxLayout; + auto layout = new QVBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); layout->addWidget(m_inspectedFile); - layout->addWidget(Core::ItemViewFind::createSearchableWrapper( - m_treeView, - Core::ItemViewFind::DarkColored, - Core::ItemViewFind::FetchMoreWhileSearching)); + layout->addWidget(ItemViewFind::createSearchableWrapper(new IncludeFinder(m_treeView, &m_model))); layout->addWidget(m_includeHierarchyInfoLabel); - setLayout(layout); connect(CppEditorPlugin::instance(), &CppEditorPlugin::includeHierarchyRequested, this, &CppIncludeHierarchyWidget::perform); - connect(Core::EditorManager::instance(), &Core::EditorManager::editorsClosed, + connect(EditorManager::instance(), &EditorManager::editorsClosed, this, &CppIncludeHierarchyWidget::editorsClosed); - -} - -CppIncludeHierarchyWidget::~CppIncludeHierarchyWidget() -{ } void CppIncludeHierarchyWidget::perform() { showNoIncludeHierarchyLabel(); - m_editor = qobject_cast<CppEditor *>(Core::EditorManager::currentEditor()); + m_editor = qobject_cast<CppEditor *>(EditorManager::currentEditor()); if (!m_editor) return; - CppEditorWidget *widget = qobject_cast<CppEditorWidget *>(m_editor->widget()); - if (!widget) - return; + QString document = m_editor->textDocument()->filePath().toString(); + m_model.buildHierarchy(document); - m_model->clear(); - m_model->buildHierarchy(m_editor, widget->textDocument()->filePath().toString()); - if (m_model->isEmpty()) - return; - - m_inspectedFile->setText(widget->textDocument()->displayName()); - m_inspectedFile->setLink(TextEditorWidget::Link(widget->textDocument()->filePath().toString())); + m_inspectedFile->setText(m_editor->textDocument()->displayName()); + m_inspectedFile->setLink(TextEditorWidget::Link(document)); - //expand "Includes" - m_treeView->expand(m_model->index(0, 0)); - //expand "Included by" - m_treeView->expand(m_model->index(1, 0)); + // expand "Includes" adn "Included by" + m_treeView->expand(m_model.index(0, 0)); + m_treeView->expand(m_model.index(1, 0)); showIncludeHierarchy(); } void CppIncludeHierarchyWidget::onItemActivated(const QModelIndex &index) { - const TextEditorWidget::Link link = index.data(LinkRole).value<TextEditorWidget::Link>(); + const auto link = index.data(LinkRole).value<TextEditorWidget::Link>(); if (link.hasValidTarget()) - Core::EditorManager::openEditorAt(link.targetFileName, - link.targetLine, - link.targetColumn, - Constants::CPPEDITOR_ID); + EditorManager::openEditorAt(link.targetFileName, + link.targetLine, + link.targetColumn, + Constants::CPPEDITOR_ID); } -void CppIncludeHierarchyWidget::editorsClosed(QList<Core::IEditor *> editors) +void CppIncludeHierarchyWidget::editorsClosed(QList<IEditor *> editors) { - foreach (Core::IEditor *editor, editors) { + foreach (IEditor *editor, editors) { if (m_editor == editor) perform(); } @@ -163,20 +438,9 @@ void CppIncludeHierarchyWidget::showIncludeHierarchy() m_includeHierarchyInfoLabel->hide(); } -// CppIncludeHierarchyStackedWidget -CppIncludeHierarchyStackedWidget::CppIncludeHierarchyStackedWidget(QWidget *parent) : - QStackedWidget(parent), - m_typeHiearchyWidgetInstance(new CppIncludeHierarchyWidget) -{ - addWidget(m_typeHiearchyWidgetInstance); -} - -CppIncludeHierarchyStackedWidget::~CppIncludeHierarchyStackedWidget() -{ - delete m_typeHiearchyWidgetInstance; -} // CppIncludeHierarchyFactory + CppIncludeHierarchyFactory::CppIncludeHierarchyFactory() { setDisplayName(tr("Include Hierarchy")); @@ -184,12 +448,16 @@ CppIncludeHierarchyFactory::CppIncludeHierarchyFactory() setId(Constants::INCLUDE_HIERARCHY_ID); } -Core::NavigationView CppIncludeHierarchyFactory::createWidget() +NavigationView CppIncludeHierarchyFactory::createWidget() { - CppIncludeHierarchyStackedWidget *w = new CppIncludeHierarchyStackedWidget; - static_cast<CppIncludeHierarchyWidget *>(w->currentWidget())->perform(); - Core::NavigationView navigationView; - navigationView.widget = w; + auto hierarchyWidget = new CppIncludeHierarchyWidget; + hierarchyWidget->perform(); + + auto stack = new QStackedWidget; + stack->addWidget(hierarchyWidget); + + NavigationView navigationView; + navigationView.widget = stack; return navigationView; } diff --git a/src/plugins/cppeditor/cppincludehierarchy.h b/src/plugins/cppeditor/cppincludehierarchy.h index b1cb25a1f7..45645a74c0 100644 --- a/src/plugins/cppeditor/cppincludehierarchy.h +++ b/src/plugins/cppeditor/cppincludehierarchy.h @@ -26,83 +26,52 @@ #pragma once #include <coreplugin/inavigationwidgetfactory.h> +#include <utils/treemodel.h> -#include <QString> -#include <QStackedWidget> -#include <QWidget> - -QT_BEGIN_NAMESPACE -class QStandardItemModel; -class QStandardItem; -class QModelIndex; -class QLabel; -QT_END_NAMESPACE - -namespace Core { class IEditor; } - -namespace TextEditor { -class BaseTextEditor; -class TextEditorLinkLabel; -} - -namespace Utils { -class AnnotatedItemDelegate; -class FileName; -} +#include <QSet> namespace CppEditor { namespace Internal { -class CppEditor; -class CppEditorWidget; -class CppInclude; -class CppIncludeHierarchyModel; -class CppIncludeHierarchyTreeView; +class CppIncludeHierarchyItem; -class CppIncludeHierarchyWidget : public QWidget +class CppIncludeHierarchyModel : public Utils::TreeModel<CppIncludeHierarchyItem> { Q_OBJECT -public: - CppIncludeHierarchyWidget(); - virtual ~CppIncludeHierarchyWidget(); + typedef Utils::TreeModel<CppIncludeHierarchyItem> base_type; - void perform(); +public: + CppIncludeHierarchyModel(); -private: - void onItemActivated(const QModelIndex &index); - void editorsClosed(QList<Core::IEditor *> editors); - void showNoIncludeHierarchyLabel(); - void showIncludeHierarchy(); + Qt::DropActions supportedDragActions() const override; + QStringList mimeTypes() const override; + QMimeData *mimeData(const QModelIndexList &indexes) const override; - CppEditorWidget *m_cppEditor; - CppIncludeHierarchyTreeView *m_treeView; - CppIncludeHierarchyModel *m_model; - Utils::AnnotatedItemDelegate *m_delegate; - TextEditor::TextEditorLinkLabel *m_inspectedFile; - QLabel *m_includeHierarchyInfoLabel; - TextEditor::BaseTextEditor *m_editor; -}; + void buildHierarchy(const QString &filePath); + QString editorFilePath() const { return m_editorFilePath; } + void setSearching(bool on); + QString toString() const; -// @todo: Pretty much the same design as the OutlineWidgetStack. Maybe we can generalize the -// outline factory so that it works for different widgets that support the same editor. -class CppIncludeHierarchyStackedWidget : public QStackedWidget -{ - Q_OBJECT -public: - CppIncludeHierarchyStackedWidget(QWidget *parent = 0); - virtual ~CppIncludeHierarchyStackedWidget(); +#if WITH_TESTS + using base_type::canFetchMore; + using base_type::fetchMore; +#endif private: - CppIncludeHierarchyWidget *m_typeHiearchyWidgetInstance; + friend class CppIncludeHierarchyItem; + QString m_editorFilePath; + QSet<QString> m_seen; + bool m_searching = false; }; class CppIncludeHierarchyFactory : public Core::INavigationWidgetFactory { Q_OBJECT + public: CppIncludeHierarchyFactory(); - Core::NavigationView createWidget(); + Core::NavigationView createWidget() override; }; } // namespace Internal diff --git a/src/plugins/cppeditor/cppincludehierarchy_test.cpp b/src/plugins/cppeditor/cppincludehierarchy_test.cpp index 8bb29f4123..95995e732a 100644 --- a/src/plugins/cppeditor/cppincludehierarchy_test.cpp +++ b/src/plugins/cppeditor/cppincludehierarchy_test.cpp @@ -25,7 +25,7 @@ #include "cppeditorplugin.h" #include "cppeditortestcase.h" -#include "cppincludehierarchymodel.h" +#include "cppincludehierarchy.h" #include <coreplugin/editormanager/editormanager.h> #include <cpptools/cppmodelmanager.h> @@ -61,6 +61,8 @@ QString toString(CppIncludeHierarchyModel &model, const QModelIndex &index, int QString toString(CppIncludeHierarchyModel &model) { + model.fetchMore(model.index(0, 0)); + model.fetchMore(model.index(1, 0)); return toString(model, model.index(0, 0)) + toString(model, model.index(1, 0)); } @@ -98,8 +100,8 @@ public: closeEditorAtEndOfTestCase(editor); // Test model - CppIncludeHierarchyModel model(0); - model.buildHierarchy(editor, fileName); + CppIncludeHierarchyModel model; + model.buildHierarchy(editor->document()->filePath().toString()); const QString actualHierarchy = toString(model); QCOMPARE(actualHierarchy, expectedHierarchy); } diff --git a/src/plugins/cppeditor/cppincludehierarchyitem.cpp b/src/plugins/cppeditor/cppincludehierarchyitem.cpp deleted file mode 100644 index 10f5fd01d6..0000000000 --- a/src/plugins/cppeditor/cppincludehierarchyitem.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "cppincludehierarchyitem.h" - -namespace CppEditor { -namespace Internal { - -CppIncludeHierarchyItem::CppIncludeHierarchyItem(const QString &filePath, - CppIncludeHierarchyItem *parent, - bool isCyclic) - : m_fileName(filePath.mid(filePath.lastIndexOf(QLatin1Char('/')) + 1)) - , m_filePath(filePath) - , m_parentItem(parent) - , m_isCyclic(isCyclic) - , m_hasChildren(false) - , m_line(0) -{ -} - -CppIncludeHierarchyItem::~CppIncludeHierarchyItem() -{ - removeChildren(); -} - -const QString &CppIncludeHierarchyItem::fileName() const -{ - return m_fileName; -} - -const QString &CppIncludeHierarchyItem::filePath() const -{ - return m_filePath; -} - -CppIncludeHierarchyItem *CppIncludeHierarchyItem::parent() const -{ - return m_parentItem; -} - -bool CppIncludeHierarchyItem::isCyclic() const -{ - return m_isCyclic; -} - -void CppIncludeHierarchyItem::appendChild(CppIncludeHierarchyItem *childItem) -{ - m_childItems.append(childItem); -} - -CppIncludeHierarchyItem *CppIncludeHierarchyItem::child(int row) -{ - return m_childItems.at(row); -} - -int CppIncludeHierarchyItem::row() const -{ - if (m_parentItem) - return m_parentItem->m_childItems.indexOf(const_cast<CppIncludeHierarchyItem*>(this)); - - return 0; -} - -int CppIncludeHierarchyItem::childCount() const -{ - return m_childItems.size(); -} - -void CppIncludeHierarchyItem::removeChildren() -{ - qDeleteAll(m_childItems); - m_childItems.clear(); -} - -bool CppIncludeHierarchyItem::needChildrenPopulate() const -{ - return m_hasChildren && m_childItems.isEmpty(); -} - -bool CppIncludeHierarchyItem::hasChildren() const -{ - return m_hasChildren; -} - -void CppIncludeHierarchyItem::setHasChildren(bool hasChildren) -{ - m_hasChildren = hasChildren; -} - -int CppIncludeHierarchyItem::line() const -{ - return m_line; -} - -void CppIncludeHierarchyItem::setLine(int line) -{ - m_line = line; -} - -} // namespace Internal -} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppincludehierarchyitem.h b/src/plugins/cppeditor/cppincludehierarchyitem.h deleted file mode 100644 index f7cd897dab..0000000000 --- a/src/plugins/cppeditor/cppincludehierarchyitem.h +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include <QList> -#include <QString> - -namespace CppEditor { -namespace Internal { - -class CppIncludeHierarchyItem -{ -public: - CppIncludeHierarchyItem(const QString &filePath, CppIncludeHierarchyItem *parent = 0, - bool isCyclic = false); - virtual ~CppIncludeHierarchyItem(); - - CppIncludeHierarchyItem *parent() const; - CppIncludeHierarchyItem *child(int row); - int childCount() const; - void appendChild(CppIncludeHierarchyItem *childItem); - void removeChildren(); - bool needChildrenPopulate() const; - int row() const; - bool isCyclic() const; - - const QString &fileName() const; - const QString &filePath() const; - bool hasChildren() const; - void setHasChildren(bool hasChildren); - int line() const; - void setLine(int line); - -private: - QString m_fileName; - QString m_filePath; - QList<CppIncludeHierarchyItem *> m_childItems; - CppIncludeHierarchyItem *m_parentItem; - bool m_isCyclic; - bool m_hasChildren; - int m_line; -}; - -} // namespace Internal -} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppincludehierarchymodel.cpp b/src/plugins/cppeditor/cppincludehierarchymodel.cpp deleted file mode 100644 index 5ad964affb..0000000000 --- a/src/plugins/cppeditor/cppincludehierarchymodel.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "cppincludehierarchymodel.h" - -#include "cppincludehierarchyitem.h" - -#include <coreplugin/fileiconprovider.h> -#include <cpptools/baseeditordocumentprocessor.h> -#include <cpptools/cppmodelmanager.h> -#include <cpptools/cpptoolsbridge.h> -#include <cpptools/editordocumenthandle.h> -#include <texteditor/texteditor.h> - -#include <cplusplus/CppDocument.h> -#include <utils/dropsupport.h> -#include <utils/qtcassert.h> - -#include <QSet> - -using namespace CPlusPlus; -using namespace CppTools; - -namespace { - -Snapshot globalSnapshot() -{ - return CppModelManager::instance()->snapshot(); -} - -} // anonymous namespace - -namespace CppEditor { -namespace Internal { - -CppIncludeHierarchyModel::CppIncludeHierarchyModel(QObject *parent) - : QAbstractItemModel(parent) - , m_rootItem(new CppIncludeHierarchyItem(QString())) - , m_includesItem(new CppIncludeHierarchyItem(tr("Includes"), m_rootItem)) - , m_includedByItem(new CppIncludeHierarchyItem(tr("Included by"), m_rootItem)) - , m_editor(0) -{ - m_rootItem->appendChild(m_includesItem); - m_rootItem->appendChild(m_includedByItem); -} - -CppIncludeHierarchyModel::~CppIncludeHierarchyModel() -{ - delete m_rootItem; -} - -QModelIndex CppIncludeHierarchyModel::index(int row, int column, const QModelIndex &parent) const -{ - if (!hasIndex(row, column, parent)) - return QModelIndex(); - - CppIncludeHierarchyItem *parentItem = parent.isValid() - ? static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()) - : m_rootItem; - - CppIncludeHierarchyItem *childItem = parentItem->child(row); - return childItem ? createIndex(row, column, childItem) : QModelIndex(); -} - -QModelIndex CppIncludeHierarchyModel::parent(const QModelIndex &index) const -{ - if (!index.isValid()) - return QModelIndex(); - - CppIncludeHierarchyItem *childItem - = static_cast<CppIncludeHierarchyItem*>(index.internalPointer()); - CppIncludeHierarchyItem *parentItem = childItem->parent(); - - if (parentItem == m_rootItem) - return QModelIndex(); - - return createIndex(parentItem->row(), 0, parentItem); -} - -int CppIncludeHierarchyModel::rowCount(const QModelIndex &parent) const -{ - CppIncludeHierarchyItem *parentItem; - - if (!parent.isValid()) - parentItem = m_rootItem; - else - parentItem = static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()); - - return parentItem->childCount(); -} - -int CppIncludeHierarchyModel::columnCount(const QModelIndex &) const -{ - return 1; -} - -QVariant CppIncludeHierarchyModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - CppIncludeHierarchyItem *item = static_cast<CppIncludeHierarchyItem*>(index.internalPointer()); - - if (!item) - return QVariant(); - - if (role == Qt::DisplayRole) { - if ((item == m_includesItem && m_includesItem->childCount() == 0) - || (item == m_includedByItem && m_includedByItem->childCount() == 0)) { - return QString(item->fileName() + QLatin1Char(' ') + tr("(none)")); - } - - if (item->isCyclic()) - return QString(item->fileName() + QLatin1Char(' ') + tr("(cyclic)")); - - return item->fileName(); - } - - if (item == m_rootItem || item == m_includesItem || item == m_includedByItem) - return QVariant(); - - switch (role) { - case Qt::ToolTipRole: - return item->filePath(); - case Qt::DecorationRole: - return Core::FileIconProvider::icon(QFileInfo(item->filePath())); - case LinkRole: { - QVariant itemLink; - TextEditor::TextEditorWidget::Link link(item->filePath(), item->line()); - itemLink.setValue(link); - return itemLink; - } - } - - return QVariant(); -} - -void CppIncludeHierarchyModel::fetchMore(const QModelIndex &parent) -{ - if (!parent.isValid()) - return; - - CppIncludeHierarchyItem *parentItem - = static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()); - Q_ASSERT(parentItem); - - if (parentItem == m_rootItem || parentItem == m_includesItem || parentItem == m_includedByItem) - return; - - if (parentItem->needChildrenPopulate()) { - const QString editorFilePath = m_editor->document()->filePath().toString(); - QSet<QString> cyclic; - cyclic << editorFilePath; - CppIncludeHierarchyItem *item = parentItem->parent(); - while (!(item == m_includesItem || item == m_includedByItem)) { - cyclic << item->filePath(); - item = item->parent(); - } - - if (item == m_includesItem) { - auto *processor = CppToolsBridge::baseEditorDocumentProcessor(editorFilePath); - QTC_ASSERT(processor, return); - const Snapshot editorDocumentSnapshot = processor->snapshot(); - buildHierarchyIncludes_helper(parentItem->filePath(), parentItem, - editorDocumentSnapshot, &cyclic); - } else { - buildHierarchyIncludedBy_helper(parentItem->filePath(), parentItem, - globalSnapshot(), &cyclic); - } - } - -} - -bool CppIncludeHierarchyModel::canFetchMore(const QModelIndex &parent) const -{ - if (!parent.isValid()) - return false; - - CppIncludeHierarchyItem *parentItem - = static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()); - Q_ASSERT(parentItem); - - if (parentItem == m_includesItem || parentItem == m_includedByItem) - return false; - - if (parentItem->needChildrenPopulate()) - return true; - - return false; -} - -void CppIncludeHierarchyModel::clear() -{ - beginResetModel(); - m_includesItem->removeChildren(); - m_includedByItem->removeChildren(); - endResetModel(); -} - -void CppIncludeHierarchyModel::buildHierarchy(TextEditor::BaseTextEditor *editor, - const QString &filePath) -{ - m_editor = editor; - beginResetModel(); - buildHierarchyIncludes(filePath); - buildHierarchyIncludedBy(filePath); - endResetModel(); -} - -bool CppIncludeHierarchyModel::hasChildren(const QModelIndex &parent) const -{ - if (!parent.isValid()) - return true; - CppIncludeHierarchyItem *parentItem - = static_cast<CppIncludeHierarchyItem*>(parent.internalPointer()); - - Q_ASSERT(parentItem); - return parentItem->hasChildren(); -} - -Qt::ItemFlags CppIncludeHierarchyModel::flags(const QModelIndex &index) const -{ - const TextEditor::TextEditorWidget::Link link - = index.data(LinkRole).value<TextEditor::TextEditorWidget::Link>(); - if (link.hasValidTarget()) - return Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsSelectable; - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -Qt::DropActions CppIncludeHierarchyModel::supportedDragActions() const -{ - return Qt::MoveAction; -} - -QStringList CppIncludeHierarchyModel::mimeTypes() const -{ - return Utils::DropSupport::mimeTypesForFilePaths(); -} - -QMimeData *CppIncludeHierarchyModel::mimeData(const QModelIndexList &indexes) const -{ - auto data = new Utils::DropMimeData; - foreach (const QModelIndex &index, indexes) { - const TextEditor::TextEditorWidget::Link link - = index.data(LinkRole).value<TextEditor::TextEditorWidget::Link>(); - if (link.hasValidTarget()) - data->addFile(link.targetFileName, link.targetLine, link.targetColumn); - } - return data; -} - -bool CppIncludeHierarchyModel::isEmpty() const -{ - return !m_includesItem->hasChildren() && !m_includedByItem->hasChildren(); -} - -void CppIncludeHierarchyModel::buildHierarchyIncludes(const QString ¤tFilePath) -{ - if (!m_editor) - return; - - const QString editorFilePath = m_editor->document()->filePath().toString(); - auto *documentProcessor = CppToolsBridge::baseEditorDocumentProcessor(editorFilePath); - QTC_ASSERT(documentProcessor, return); - const Snapshot editorDocumentSnapshot = documentProcessor->snapshot(); - QSet<QString> cyclic; - buildHierarchyIncludes_helper(currentFilePath, m_includesItem, editorDocumentSnapshot, &cyclic); -} - -void CppIncludeHierarchyModel::buildHierarchyIncludes_helper(const QString &filePath, - CppIncludeHierarchyItem *parent, - Snapshot snapshot, - QSet<QString> *cyclic, - bool recursive) -{ - Document::Ptr doc = snapshot.document(filePath); - if (!doc) - return; - - parent->setHasChildren(doc->resolvedIncludes().size() > 0); - if (!recursive) - return; - - cyclic->insert(filePath); - - foreach (const Document::Include &includeFile, doc->resolvedIncludes()) { - const QString includedFilePath = includeFile.resolvedFileName(); - CppIncludeHierarchyItem *item = 0; - - if (cyclic->contains(includedFilePath)) { - item = new CppIncludeHierarchyItem(includedFilePath, parent, true); - parent->appendChild(item); - continue; - } - item = new CppIncludeHierarchyItem(includedFilePath, parent); - parent->appendChild(item); - buildHierarchyIncludes_helper(includedFilePath, item, snapshot, cyclic, false); - - } - cyclic->remove(filePath); -} - -void CppIncludeHierarchyModel::buildHierarchyIncludedBy(const QString ¤tFilePath) -{ - QSet<QString> cyclic; - buildHierarchyIncludedBy_helper(currentFilePath, m_includedByItem, globalSnapshot(), &cyclic); -} - -void CppIncludeHierarchyModel::buildHierarchyIncludedBy_helper(const QString &filePath, - CppIncludeHierarchyItem *parent, - Snapshot snapshot, - QSet<QString> *cyclic, - bool recursive) -{ - cyclic->insert(filePath); - Snapshot::const_iterator citEnd = snapshot.end(); - for (Snapshot::const_iterator cit = snapshot.begin(); cit != citEnd; ++cit) { - const QString filePathFromSnapshot = cit.key().toString(); - Document::Ptr doc = cit.value(); - foreach (const Document::Include &includeFile, doc->resolvedIncludes()) { - const QString includedFilePath = includeFile.resolvedFileName(); - - if (includedFilePath == filePath) { - parent->setHasChildren(true); - if (!recursive) { - cyclic->remove(filePath); - return; - } - - const bool isCyclic = cyclic->contains(filePathFromSnapshot); - CppIncludeHierarchyItem *item = new CppIncludeHierarchyItem(filePathFromSnapshot, - parent, - isCyclic); - item->setLine(includeFile.line()); - parent->appendChild(item); - - if (isCyclic) - continue; - - buildHierarchyIncludedBy_helper(filePathFromSnapshot, item, snapshot, cyclic, - false); - } - } - } - cyclic->remove(filePath); -} - -} // namespace Internal -} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppincludehierarchymodel.h b/src/plugins/cppeditor/cppincludehierarchymodel.h deleted file mode 100644 index 2bc80bcb12..0000000000 --- a/src/plugins/cppeditor/cppincludehierarchymodel.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include <QAbstractItemModel> - -namespace { - -enum ItemRole { - AnnotationRole = Qt::UserRole + 1, - LinkRole -}; - -} // Anonymous - -namespace CPlusPlus { class Snapshot; } -namespace TextEditor { class BaseTextEditor; } - -namespace CppEditor { -namespace Internal { - -class CppEditor; -class CppIncludeHierarchyItem; - -class CppIncludeHierarchyModel : public QAbstractItemModel -{ - Q_OBJECT -public: - explicit CppIncludeHierarchyModel(QObject *parent); - ~CppIncludeHierarchyModel(); - - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex &index) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - void fetchMore(const QModelIndex &parent); - bool canFetchMore(const QModelIndex &parent) const; - bool hasChildren(const QModelIndex &parent) const; - Qt::ItemFlags flags(const QModelIndex &index) const; - - Qt::DropActions supportedDragActions() const; - QStringList mimeTypes() const; - QMimeData *mimeData(const QModelIndexList &indexes) const; - - void clear(); - void buildHierarchy(TextEditor::BaseTextEditor *editor, const QString &filePath); - bool isEmpty() const; - -private: - void buildHierarchyIncludes(const QString ¤tFilePath); - void buildHierarchyIncludes_helper(const QString &filePath, CppIncludeHierarchyItem *parent, - CPlusPlus::Snapshot snapshot, - QSet<QString> *cyclic, bool recursive = true); - void buildHierarchyIncludedBy(const QString ¤tFilePath); - void buildHierarchyIncludedBy_helper(const QString &filePath, CppIncludeHierarchyItem *parent, - CPlusPlus::Snapshot snapshot, QSet<QString> *cyclic, - bool recursive = true); - - CppIncludeHierarchyItem *m_rootItem; - CppIncludeHierarchyItem *m_includesItem; - CppIncludeHierarchyItem *m_includedByItem; - TextEditor::BaseTextEditor *m_editor; -}; - -} // namespace Internal -} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppincludehierarchytreeview.cpp b/src/plugins/cppeditor/cppincludehierarchytreeview.cpp deleted file mode 100644 index c363eb229c..0000000000 --- a/src/plugins/cppeditor/cppincludehierarchytreeview.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "cppincludehierarchytreeview.h" - -#include <QKeyEvent> - -namespace CppEditor { -namespace Internal { - -CppIncludeHierarchyTreeView::CppIncludeHierarchyTreeView(QWidget *parent/* = 0*/) - : NavigationTreeView(parent) -{ - setDragEnabled(true); - setDragDropMode(QAbstractItemView::DragOnly); -} - -void CppIncludeHierarchyTreeView::keyPressEvent(QKeyEvent *event) -{ - switch (event->key()) { - case Qt::Key_Asterisk: - QAbstractItemView::keyPressEvent(event); - return; - } - - NavigationTreeView::keyPressEvent(event); -} - -} // namespace Internal -} // namespace CppEditor diff --git a/src/plugins/cppeditor/cppincludehierarchytreeview.h b/src/plugins/cppeditor/cppincludehierarchytreeview.h deleted file mode 100644 index 083b6f1614..0000000000 --- a/src/plugins/cppeditor/cppincludehierarchytreeview.h +++ /dev/null @@ -1,42 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Przemyslaw Gorszkowski <pgorszkowski@gmail.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include <utils/navigationtreeview.h> - -namespace CppEditor { -namespace Internal { - -class CppIncludeHierarchyTreeView : public Utils::NavigationTreeView -{ -public: - CppIncludeHierarchyTreeView(QWidget *parent = 0); -protected: - void keyPressEvent(QKeyEvent *event); -}; - -} // namespace Internal -} // namespace CppEditor diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index e3c7e7a5a2..bd79057f11 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1516,12 +1516,15 @@ void CdbEngine::postFetchMemory(const MemoryViewCookie &cookie) str << cookie.address << ' ' << cookie.length; cmd.args = args; cmd.callback = [this, cookie](const DebuggerResponse &response) { - if (response.resultClass == ResultDone && cookie.agent) { + if (!cookie.agent) + return; + if (response.resultClass == ResultDone) { const QByteArray data = QByteArray::fromHex(response.data.data().toUtf8()); if (unsigned(data.size()) == cookie.length) cookie.agent->addData(cookie.address, data); } else { showMessage(response.data["msg"].data(), LogWarning); + cookie.agent->addData(cookie.address, QByteArray(int(cookie.length), char())); } }; runCommand(cmd); diff --git a/src/plugins/debugger/debuggerkitconfigwidget.cpp b/src/plugins/debugger/debuggerkitconfigwidget.cpp index 0a0aa8ce2c..34f68fe6f1 100644 --- a/src/plugins/debugger/debuggerkitconfigwidget.cpp +++ b/src/plugins/debugger/debuggerkitconfigwidget.cpp @@ -142,16 +142,6 @@ void DebuggerKitConfigWidget::currentDebuggerChanged(int) m_kit->setValue(DebuggerKitInformation::id(), id); } -int DebuggerKitConfigWidget::indexOf(const QVariant &id) -{ - QTC_ASSERT(id.isValid(), return -1); - for (int i = 0; i < m_comboBox->count(); ++i) { - if (id == m_comboBox->itemData(i)) - return i; - } - return -1; -} - QVariant DebuggerKitConfigWidget::currentId() const { return m_comboBox->itemData(m_comboBox->currentIndex()); diff --git a/src/plugins/debugger/debuggerkitconfigwidget.h b/src/plugins/debugger/debuggerkitconfigwidget.h index ff89d4e70d..9fbe1f124d 100644 --- a/src/plugins/debugger/debuggerkitconfigwidget.h +++ b/src/plugins/debugger/debuggerkitconfigwidget.h @@ -68,7 +68,6 @@ private: void manageDebuggers(); void currentDebuggerChanged(int idx); - int indexOf(const QVariant &id); QVariant currentId() const; void updateComboBox(const QVariant &id); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 5f118ed6cd..abf5498be0 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1650,8 +1650,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, cmd->setAttribute(Command::CA_UpdateText); debugMenu->addAction(cmd); - cmd = ActionManager::registerAction(m_stepOutAction, - Constants::STEPOUT, cppDebuggercontext); + cmd = ActionManager::registerAction(m_stepOutAction, Constants::STEPOUT); cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+T") : tr("Shift+F11"))); cmd->setAttribute(Command::CA_Hide); debugMenu->addAction(cmd); diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index a0ead85150..8c18d420fa 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -441,17 +441,19 @@ static DebuggerRunControl *doCreate(DebuggerRunParameters rp, RunConfiguration * if (rp.languages & QmlLanguage) { if (rp.device && rp.device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { - QTcpServer server; - const bool canListen = server.listen(QHostAddress::LocalHost) - || server.listen(QHostAddress::LocalHostIPv6); - if (!canListen) { - errors->append(DebuggerPlugin::tr("Not enough free ports for QML debugging.") + ' '); - return 0; + if (rp.qmlServer.host.isEmpty() || !rp.qmlServer.port.isValid()) { + QTcpServer server; + const bool canListen = server.listen(QHostAddress::LocalHost) + || server.listen(QHostAddress::LocalHostIPv6); + if (!canListen) { + errors->append(DebuggerPlugin::tr("Not enough free ports for QML debugging.") + ' '); + return 0; + } + TcpServerConnection conn; + conn.host = server.serverAddress().toString(); + conn.port = Utils::Port(server.serverPort()); + rp.qmlServer = conn; } - TcpServerConnection conn; - conn.host = server.serverAddress().toString(); - conn.port = Utils::Port(server.serverPort()); - rp.qmlServer = conn; // Makes sure that all bindings go through the JavaScript engine, so that // breakpoints are actually hit! diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index 11319c47c9..313cecefd7 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -49,7 +49,8 @@ using namespace Utils; static const char* qtBuildPaths[] = { "Q:/qt5_workdir/w/s", "C:/work/build/qt5_workdir/w/s", - "c:/users/qt/work/qt" + "c:/users/qt/work/qt", + "c:/Users/qt/work/install" }; #elif defined(Q_OS_MAC) static const char* qtBuildPaths[] = {}; diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index e0969d0221..eab055ba4f 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -91,6 +91,10 @@ void PdbEngine::postDirectCommand(const QString &command) void PdbEngine::runCommand(const DebuggerCommand &cmd) { + if (state() == EngineSetupRequested) { // cmd has been triggered too early + showMessage("IGNORED COMMAND: " + cmd.function); + return; + } QTC_ASSERT(m_proc.state() == QProcess::Running, notifyEngineIll()); QString command = "qdebug('" + cmd.function + "'," + cmd.argsToPython() + ")"; showMessage(command, LogInput); diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 0d4ec99880..107d3708ba 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -1084,7 +1084,7 @@ void QmlEngine::quitDebugger() d->noDebugOutputTimer.stop(); d->automaticConnect = false; d->retryOnConnectFail = false; - DebuggerEngine::quitDebugger(); + shutdownInferior(); } void QmlEngine::disconnected() @@ -2150,7 +2150,7 @@ void QmlEnginePrivate::handleFrame(const QVariantMap &response) StackHandler *stackHandler = engine->stackHandler(); WatchHandler * watchHandler = engine->watchHandler(); - watchHandler->notifyUpdateStarted(); + watchHandler->notifyUpdateStarted({"local"}); const int frameIndex = stackHandler->currentIndex(); if (frameIndex < 0) diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 8143dc8767..3878cb337b 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -2042,6 +2042,13 @@ void WatchHandler::notifyUpdateFinished() foreach (auto item, toRemove) m_model->destroyItem(item); + m_model->forAllItems([this](WatchItem *item) { + if (item->wantsChildren && isExpandedIName(item->iname)) { + m_model->m_engine->showMessage(QString("ADJUSTING CHILD EXPECTATION FOR " + item->iname)); + item->wantsChildren = false; + } + }); + m_model->m_contentsValid = true; updateWatchersWindow(); m_model->reexpandItems(); diff --git a/src/plugins/help/localhelpmanager.cpp b/src/plugins/help/localhelpmanager.cpp index 929286687d..dee3ef7332 100644 --- a/src/plugins/help/localhelpmanager.cpp +++ b/src/plugins/help/localhelpmanager.cpp @@ -81,7 +81,7 @@ static QString defaultFallbackFontFamily() if (Utils::HostOsInfo::isMacHost()) return QString("Helvetica"); if (Utils::HostOsInfo::isAnyUnixHost()) - return QString("sans-serif"); + return QString("Sans Serif"); return QString("Arial"); } diff --git a/src/plugins/nim/project/nimbuildconfiguration.cpp b/src/plugins/nim/project/nimbuildconfiguration.cpp index 6837063fbf..d382ec5adb 100644 --- a/src/plugins/nim/project/nimbuildconfiguration.cpp +++ b/src/plugins/nim/project/nimbuildconfiguration.cpp @@ -106,14 +106,12 @@ bool NimBuildConfiguration::canRestore(const QVariantMap &map) bool NimBuildConfiguration::hasNimCompilerBuildStep() const { BuildStepList *steps = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD); - QTC_ASSERT(steps, return false); - return steps->contains(Constants::C_NIMCOMPILERBUILDSTEP_ID); + return steps ? steps->contains(Constants::C_NIMCOMPILERBUILDSTEP_ID) : false; } bool NimBuildConfiguration::hasNimCompilerCleanStep() const { BuildStepList *steps = stepList(ProjectExplorer::Constants::BUILDSTEPS_CLEAN); - QTC_ASSERT(steps, return false); return steps ? steps->contains(Constants::C_NIMCOMPILERCLEANSTEP_ID) : false; } diff --git a/src/plugins/nim/project/nimrunconfiguration.cpp b/src/plugins/nim/project/nimrunconfiguration.cpp index 3ac4724e0b..7b9e43ab47 100644 --- a/src/plugins/nim/project/nimrunconfiguration.cpp +++ b/src/plugins/nim/project/nimrunconfiguration.cpp @@ -80,6 +80,7 @@ Runnable NimRunConfiguration::runnable() const result.executable = m_executable; result.commandLineArguments = m_argumentAspect->arguments(); result.workingDirectory = m_workingDirectoryAspect->workingDirectory().toString(); + result.environment = m_localEnvironmentAspect->environment(); return result; } diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 58869edf60..1f22cf65ed 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -110,7 +110,6 @@ private: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; - mutable QImage selectionGradient; ListWidget *m_listWidget; }; @@ -128,9 +127,6 @@ void TargetSelectorDelegate::paint(QPainter *painter, painter->save(); painter->setClipping(false); - if (selectionGradient.isNull()) - selectionGradient.load(QLatin1String(":/projectexplorer/images/targetpanel_gradient.png")); - if (option.state & QStyle::State_Selected) { const QColor color = (option.state & QStyle::State_HasFocus) ? option.palette.highlight().color() : @@ -139,6 +135,7 @@ void TargetSelectorDelegate::paint(QPainter *painter, painter->fillRect(option.rect, color); } else { painter->fillRect(option.rect, color.darker(140)); + static const QImage selectionGradient(":/projectexplorer/images/targetpanel_gradient.png"); StyleHelper::drawCornerImage(selectionGradient, painter, option.rect.adjusted(0, 0, 0, -1), 5, 5, 5, 5); const QRectF borderRect = QRectF(option.rect).adjusted(0.5, 0.5, -0.5, -0.5); painter->setPen(QColor(255, 255, 255, 60)); @@ -1596,7 +1593,7 @@ void MiniProjectTargetSelector::paintEvent(QPaintEvent *) if (creatorTheme()->flag(Theme::DrawTargetSelectorBottom)) { // draw thicker border on the bottom QRect bottomRect(0, rect().height() - 8, rect().width(), 8); - static QImage image(QLatin1String(":/projectexplorer/images/targetpanel_bottom.png")); + static const QImage image(":/projectexplorer/images/targetpanel_bottom.png"); StyleHelper::drawCornerImage(image, &painter, bottomRect, 1, 1, 1, 1); } } diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index eba1144f98..c2266a5086 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -1229,7 +1229,7 @@ QPair<ProFile *, QStringList> QmakePriFileNode::readProFile(const QString &file) QMakeVfs vfs; QtSupport::ProMessageHandler handler; QMakeParser parser(0, &vfs, &handler); - includeFile = parser.parsedProBlock(contents, file, 1); + includeFile = parser.parsedProBlock(QStringRef(&contents), file, 1); } return qMakePair(includeFile, lines); } @@ -1264,7 +1264,8 @@ bool QmakePriFileNode::renameFile(const QString &oldName, // We need to re-parse here: The file has changed. QMakeParser parser(0, 0, 0); - includeFile = parser.parsedProBlock(lines.join(QLatin1Char('\n')), + QString contents = lines.join(QLatin1Char('\n')); + includeFile = parser.parsedProBlock(QStringRef(&contents), m_projectFilePath.toString(), 1, QMakeParser::FullGrammar); QTC_ASSERT(includeFile, return false); // The file should still be valid after what we did. diff --git a/src/plugins/qmldesigner/components/componentcore/theming.cpp b/src/plugins/qmldesigner/components/componentcore/theming.cpp index c2ba9b37d9..d1429ff45b 100644 --- a/src/plugins/qmldesigner/components/componentcore/theming.cpp +++ b/src/plugins/qmldesigner/components/componentcore/theming.cpp @@ -33,13 +33,6 @@ namespace QmlDesigner { -QColor midtone(const QColor &a, const QColor &b) -{ - QColor alphaB = b; - alphaB.setAlpha(128); - return Utils::StyleHelper::alphaBlendedColors(a ,alphaB); -} - void Theming::insertTheme(QQmlPropertyMap *map) { const QVariantHash creatorTheme = Utils::creatorTheme()->values(); @@ -47,6 +40,7 @@ void Theming::insertTheme(QQmlPropertyMap *map) map->insert(it.key(), it.value()); /* Define QmlDesigner colors and remove alpha channels */ + const QColor backgroundColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_BackgroundColor); const QColor panelStatusBarBackgroundColor = Utils::creatorTheme()->color(Utils::Theme::PanelStatusBarBackgroundColor); const QColor fancyToolButtonSelectedColor = Utils::creatorTheme()->color(Utils::Theme::FancyToolButtonSelectedColor); const QColor darkerBackground = Utils::StyleHelper::alphaBlendedColors(panelStatusBarBackgroundColor, fancyToolButtonSelectedColor); @@ -65,7 +59,7 @@ void Theming::insertTheme(QQmlPropertyMap *map) } map->insert("QmlDesignerBackgroundColorDarker", darkerBackground); - map->insert("QmlDesignerBackgroundColorDarkAlternate", midtone(panelStatusBarBackgroundColor, buttonColor)); + map->insert("QmlDesignerBackgroundColorDarkAlternate", backgroundColor); map->insert("QmlDesignerTabLight", tabLight); map->insert("QmlDesignerTabDark", tabDark); map->insert("QmlDesignerButtonColor", buttonColor); diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index 4229d69776..696813a8a6 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -320,13 +320,13 @@ void DesignModeWidget::setup() connect(m_warningWidget.data(), &DocumentWarningWidget::gotoCodeClicked, [=] (const QString &filePath, int codeLine, int codeColumn) { Q_UNUSED(filePath); + + QTC_ASSERT(textEditor(), return;); QTC_ASSERT(textEditor()->textDocument()->filePath().toString() == filePath, - qDebug() << Q_FUNC_INFO << textEditor()->textDocument()->filePath().toString() << - filePath; ); - textEditor()->gotoLine(codeLine, codeColumn); - Core::ModeManager::activateMode(Core::Constants::MODE_EDIT); - } - ); + qDebug() << Q_FUNC_INFO << textEditor()->textDocument()->filePath().toString() << filePath; ); + textEditor()->gotoLine(codeLine, codeColumn); + Core::ModeManager::activateMode(Core::Constants::MODE_EDIT); + }); QList<Core::SideBarItem*> sideBarItems; QList<Core::SideBarItem*> leftSideBarItems; diff --git a/src/plugins/resourceeditor/resourceeditorconstants.h b/src/plugins/resourceeditor/resourceeditorconstants.h index b0f9b3ebf5..ae3fb962e1 100644 --- a/src/plugins/resourceeditor/resourceeditorconstants.h +++ b/src/plugins/resourceeditor/resourceeditorconstants.h @@ -39,7 +39,7 @@ const char C_RESOURCE_MIMETYPE[] = "application/vnd.qt.xml.resource"; const char C_ADD_PREFIX[] = "ResourceEditor.AddPrefix"; const char C_REMOVE_PREFIX[] = "ResourceEditor.RemovePrefix"; const char C_RENAME_PREFIX[] = "ResourceEditor.RenamePrefix"; -const char C_REMOVE_NON_EXISTING[] = "RessourceEditor.RemoveNonExistign"; +const char C_REMOVE_NON_EXISTING[] = "ResourceEditor.RemoveNonExisting"; const char C_REMOVE_FILE[] = "ResourceEditor.RemoveFile"; const char C_RENAME_FILE[] = "ResourceEditor.RenameFile"; diff --git a/src/shared/proparser/proitems.cpp b/src/shared/proparser/proitems.cpp index 1a22a3c50b..795b8b4564 100644 --- a/src/shared/proparser/proitems.cpp +++ b/src/shared/proparser/proitems.cpp @@ -362,6 +362,11 @@ static QString ProStringList_join(const ProStringList &this_, const QChar *sep, return res; } +QString ProStringList::join(const ProString &sep) const +{ + return ProStringList_join(*this, sep.constData(), sep.size()); +} + QString ProStringList::join(const QString &sep) const { return ProStringList_join(*this, sep.constData(), sep.size()); @@ -388,7 +393,7 @@ void ProStringList::removeAll(const char *str) void ProStringList::removeEach(const ProStringList &value) { - foreach (const ProString &str, value) + for (const ProString &str : value) if (!str.isEmpty()) removeAll(str); } @@ -421,7 +426,7 @@ void ProStringList::removeDuplicates() void ProStringList::insertUnique(const ProStringList &value) { - foreach (const ProString &str, value) + for (const ProString &str : value) if (!str.isEmpty() && !contains(str)) append(str); } @@ -429,7 +434,7 @@ void ProStringList::insertUnique(const ProStringList &value) ProStringList::ProStringList(const QStringList &list) { reserve(list.size()); - foreach (const QString &str, list) + for (const QString &str : list) *this << ProString(str); } @@ -437,8 +442,8 @@ QStringList ProStringList::toQStringList() const { QStringList ret; ret.reserve(size()); - for (int i = 0; i < size(); i++) // foreach causes MSVC2010 ICE - ret << at(i).toQString(); + for (const auto &e : *this) + ret.append(e.toQString()); return ret; } diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index d6bc4fe1cb..31e662bcf0 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -96,6 +96,7 @@ public: bool operator!=(const QString &other) const { return !(*this == other); } bool operator!=(QLatin1String other) const { return !(*this == other); } bool operator!=(const char *other) const { return !(*this == other); } + bool operator<(const ProString &other) const { return toQStringRef() < other.toQStringRef(); } bool isNull() const { return m_string.isNull(); } bool isEmpty() const { return !m_length; } int length() const { return m_length; } @@ -126,8 +127,9 @@ public: bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, 0, cs) >= 0; } bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(QLatin1String(s), 0, cs) >= 0; } bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, 0, cs) >= 0; } - int toInt(bool *ok = 0, int base = 10) const { return toQString().toInt(ok, base); } // XXX optimize - short toShort(bool *ok = 0, int base = 10) const { return toQString().toShort(ok, base); } // XXX optimize + int toLongLong(bool *ok = 0, int base = 10) const { return toQStringRef().toLongLong(ok, base); } + int toInt(bool *ok = 0, int base = 10) const { return toQStringRef().toInt(ok, base); } + short toShort(bool *ok = 0, int base = 10) const { return toQStringRef().toShort(ok, base); } uint hash() const { return m_hash; } static uint hash(const QChar *p, int n); @@ -228,6 +230,7 @@ public: int length() const { return size(); } + QString join(const ProString &sep) const; QString join(const QString &sep) const; QString join(QChar sep) const; @@ -360,6 +363,8 @@ class ProFunctionDef { public: ProFunctionDef(ProFile *pro, int offset) : m_pro(pro), m_offset(offset) { m_pro->ref(); } ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); } + ProFunctionDef(ProFunctionDef &&other) Q_DECL_NOTHROW + : m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; } ~ProFunctionDef() { m_pro->deref(); } ProFunctionDef &operator=(const ProFunctionDef &o) { @@ -371,6 +376,18 @@ public: } return *this; } + ProFunctionDef &operator=(ProFunctionDef &&other) Q_DECL_NOTHROW + { + ProFunctionDef moved(std::move(other)); + swap(moved); + return *this; + } + void swap(ProFunctionDef &other) Q_DECL_NOTHROW + { + qSwap(m_pro, other.m_pro); + qSwap(m_offset, other.m_offset); + } + ProFile *pro() const { return m_pro; } const ushort *tokPtr() const { return m_pro->tokPtr() + m_offset; } private: diff --git a/src/shared/proparser/prowriter.cpp b/src/shared/proparser/prowriter.cpp index 700e134c1b..d49c3aa864 100644 --- a/src/shared/proparser/prowriter.cpp +++ b/src/shared/proparser/prowriter.cpp @@ -175,7 +175,7 @@ QString ProWriter::compileScope(const QString &scope) if (scope.isEmpty()) return QString(); QMakeParser parser(0, 0, 0); - ProFile *includeFile = parser.parsedProBlock(scope, QLatin1String("no-file"), 1); + ProFile *includeFile = parser.parsedProBlock(QStringRef(&scope), QLatin1String("no-file"), 1); if (!includeFile) return QString(); QString result = includeFile->items(); diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index f5868c5de0..8ceebd9cf0 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -52,6 +52,8 @@ #include <utime.h> #include <errno.h> #include <unistd.h> +#include <signal.h> +#include <sys/wait.h> #include <sys/stat.h> #include <sys/utsname.h> #else @@ -62,9 +64,11 @@ #ifdef Q_OS_WIN32 #define QT_POPEN _popen +#define QT_POPEN_READ "rb" #define QT_PCLOSE _pclose #else #define QT_POPEN popen +#define QT_POPEN_READ "r" #define QT_PCLOSE pclose #endif @@ -75,9 +79,10 @@ QT_BEGIN_NAMESPACE #define fL1S(s) QString::fromLatin1(s) enum ExpandFunc { - E_INVALID = 0, E_MEMBER, E_FIRST, E_LAST, E_SIZE, E_CAT, E_FROMFILE, E_EVAL, E_LIST, - E_SPRINTF, E_FORMAT_NUMBER, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION, - E_FIND, E_SYSTEM, E_UNIQUE, E_REVERSE, E_QUOTE, E_ESCAPE_EXPAND, + E_INVALID = 0, E_MEMBER, E_STR_MEMBER, E_FIRST, E_TAKE_FIRST, E_LAST, E_TAKE_LAST, + E_SIZE, E_STR_SIZE, E_CAT, E_FROMFILE, E_EVAL, E_LIST, E_SPRINTF, E_FORMAT_NUMBER, + E_NUM_ADD, E_JOIN, E_SPLIT, E_BASENAME, E_DIRNAME, E_SECTION, + E_FIND, E_SYSTEM, E_UNIQUE, E_SORTED, E_REVERSE, E_QUOTE, E_ESCAPE_EXPAND, E_UPPER, E_LOWER, E_TITLE, E_FILES, E_PROMPT, E_RE_ESCAPE, E_VAL_ESCAPE, E_REPLACE, E_SORT_DEPENDS, E_RESOLVE_DEPENDS, E_ENUMERATE_VARS, E_SHADOWED, E_ABSOLUTE_PATH, E_RELATIVE_PATH, E_CLEAN_PATH, @@ -99,15 +104,20 @@ void QMakeEvaluator::initFunctionStatics() const ExpandFunc func; } expandInits[] = { { "member", E_MEMBER }, + { "str_member", E_STR_MEMBER }, { "first", E_FIRST }, + { "take_first", E_TAKE_FIRST }, { "last", E_LAST }, + { "take_last", E_TAKE_LAST }, { "size", E_SIZE }, + { "str_size", E_STR_SIZE }, { "cat", E_CAT }, { "fromfile", E_FROMFILE }, { "eval", E_EVAL }, { "list", E_LIST }, { "sprintf", E_SPRINTF }, { "format_number", E_FORMAT_NUMBER }, + { "num_add", E_NUM_ADD }, { "join", E_JOIN }, { "split", E_SPLIT }, { "basename", E_BASENAME }, @@ -116,6 +126,7 @@ void QMakeEvaluator::initFunctionStatics() { "find", E_FIND }, { "system", E_SYSTEM }, { "unique", E_UNIQUE }, + { "sorted", E_SORTED }, { "reverse", E_REVERSE }, { "quote", E_QUOTE }, { "escape_expand", E_ESCAPE_EXPAND }, @@ -140,6 +151,7 @@ void QMakeEvaluator::initFunctionStatics() { "shell_quote", E_SHELL_QUOTE }, { "getenv", E_GETENV }, }; + statics.expands.reserve((int)(sizeof(expandInits)/sizeof(expandInits[0]))); for (unsigned i = 0; i < sizeof(expandInits)/sizeof(expandInits[0]); ++i) statics.expands.insert(ProKey(expandInits[i].name), expandInits[i].func); @@ -179,16 +191,59 @@ void QMakeEvaluator::initFunctionStatics() { "touch", T_TOUCH }, { "cache", T_CACHE }, }; + statics.functions.reserve((int)(sizeof(testInits)/sizeof(testInits[0]))); for (unsigned i = 0; i < sizeof(testInits)/sizeof(testInits[0]); ++i) statics.functions.insert(ProKey(testInits[i].name), testInits[i].func); } -static bool isTrue(const ProString &_str, QString &tmp) +static bool isTrue(const ProString &str) { - const QString &str = _str.toQString(tmp); return !str.compare(statics.strtrue, Qt::CaseInsensitive) || str.toInt(); } +bool +QMakeEvaluator::getMemberArgs(const ProKey &func, int srclen, const ProStringList &args, + int *start, int *end) +{ + *start = 0, *end = 0; + if (args.count() >= 2) { + bool ok = true; + const ProString &start_str = args.at(1); + *start = start_str.toInt(&ok); + if (!ok) { + if (args.count() == 2) { + int dotdot = start_str.indexOf(statics.strDotDot); + if (dotdot != -1) { + *start = start_str.left(dotdot).toInt(&ok); + if (ok) + *end = start_str.mid(dotdot+2).toInt(&ok); + } + } + if (!ok) { + evalError(fL1S("%1() argument 2 (start) '%2' invalid.") + .arg(func.toQString(m_tmp1), start_str.toQString(m_tmp2))); + return false; + } + } else { + *end = *start; + if (args.count() == 3) + *end = args.at(2).toInt(&ok); + if (!ok) { + evalError(fL1S("%1() argument 3 (end) '%2' invalid.") + .arg(func.toQString(m_tmp1), args.at(2).toQString(m_tmp2))); + return false; + } + } + } + if (*start < 0) + *start += srclen; + if (*end < 0) + *end += srclen; + if (*start < 0 || *start >= srclen || *end < 0 || *end >= srclen) + return false; + return true; +} + #if defined(Q_OS_WIN) && defined(PROEVALUATOR_FULL) static QString windowsErrorCode() { @@ -285,19 +340,26 @@ static void insertJsonKeyValue(const QString &key, const QStringList &values, Pr static void addJsonArray(const QJsonArray &array, const QString &keyPrefix, ProValueMap *map) { QStringList keys; - for (int i = 0; i < array.count(); ++i) { - keys.append(QString::number(i)); - addJsonValue(array.at(i), keyPrefix + QString::number(i), map); + const int size = array.count(); + keys.reserve(size); + for (int i = 0; i < size; ++i) { + const QString number = QString::number(i); + keys.append(number); + addJsonValue(array.at(i), keyPrefix + number, map); } insertJsonKeyValue(keyPrefix + QLatin1String("_KEYS_"), keys, map); } static void addJsonObject(const QJsonObject &object, const QString &keyPrefix, ProValueMap *map) { - foreach (const QString &key, object.keys()) - addJsonValue(object.value(key), keyPrefix + key, map); - - insertJsonKeyValue(keyPrefix + QLatin1String("_KEYS_"), object.keys(), map); + QStringList keys; + keys.reserve(object.size()); + for (auto it = object.begin(), end = object.end(); it != end; ++it) { + const QString key = it.key(); + keys.append(key); + addJsonValue(it.value(), keyPrefix + key, map); + } + insertJsonKeyValue(keyPrefix + QLatin1String("_KEYS_"), keys, map); } static void addJsonValue(const QJsonValue &value, const QString &keyPrefix, ProValueMap *map) @@ -323,11 +385,16 @@ static void addJsonValue(const QJsonValue &value, const QString &keyPrefix, ProV } } -static QMakeEvaluator::VisitReturn parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value) +QMakeEvaluator::VisitReturn QMakeEvaluator::parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value) { - QJsonDocument document = QJsonDocument::fromJson(json); - if (document.isNull()) + QJsonParseError error; + QJsonDocument document = QJsonDocument::fromJson(json, &error); + if (document.isNull()) { + if (error.error != QJsonParseError::NoError) + evalError(fL1S("Error parsing json at offset %1: %2") + .arg(error.offset).arg(error.errorString())); return QMakeEvaluator::ReturnFalse; + } QString currentKey = into + QLatin1Char('.'); @@ -344,10 +411,10 @@ static QMakeEvaluator::VisitReturn parseJsonInto(const QByteArray &json, const Q QMakeEvaluator::VisitReturn QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode, - const QString &contents) + bool exe, const QString &contents) { QString errStr; - if (!m_vfs->writeFile(fn, mode, contents, &errStr)) { + if (!m_vfs->writeFile(fn, mode, exe, contents, &errStr)) { evalError(fL1S("Cannot write %1file %2: %3") .arg(ctx, QDir::toNativeSeparators(fn), errStr)); return ReturnFalse; @@ -401,7 +468,7 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args) const #else if (FILE *proc = QT_POPEN(QString(QLatin1String("cd ") + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory())) - + QLatin1String(" && ") + args).toLocal8Bit().constData(), "r")) { + + QLatin1String(" && ") + args).toLocal8Bit().constData(), QT_POPEN_READ)) { while (!feof(proc)) { char buff[10 * 1024]; int read_in = int(fread(buff, 1, sizeof(buff), proc)); @@ -411,6 +478,9 @@ QByteArray QMakeEvaluator::getCommandOutput(const QString &args) const } QT_PCLOSE(proc); } +# ifdef Q_OS_WIN + out.replace("\r\n", "\n"); +# endif #endif return out; } @@ -421,11 +491,11 @@ void QMakeEvaluator::populateDeps( QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees, QMultiMap<int, ProString> &rootSet) const { - foreach (const ProString &item, deps) + for (const ProString &item : deps) if (!dependencies.contains(item.toKey())) { QSet<ProKey> &dset = dependencies[item.toKey()]; // Always create entry ProStringList depends; - foreach (const ProString &suffix, suffixes) + for (const ProString &suffix : suffixes) depends += values(ProKey(prefix + item + suffix)); if (depends.isEmpty()) { rootSet.insert(first(ProKey(prefix + item + priosfx)).toInt(), item); @@ -462,9 +532,9 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( } else { var = args[0]; sep = args.at(1).toQString(); - beg = args.at(2).toQString(m_tmp2).toInt(); + beg = args.at(2).toInt(); if (args.count() == 4) - end = args.at(3).toQString(m_tmp2).toInt(); + end = args.at(3).toInt(); } } else { if (args.count() != 1) { @@ -480,14 +550,15 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( } } if (!var.isEmpty()) { + const auto strings = values(map(var)); if (regexp) { QRegExp sepRx(sep); - foreach (const ProString &str, values(map(var))) { + for (const ProString &str : strings) { const QString &rstr = str.toQString(m_tmp1).section(sepRx, beg, end); ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr).setSource(str)); } } else { - foreach (const ProString &str, values(map(var))) { + for (const ProString &str : strings) { const QString &rstr = str.toQString(m_tmp1).section(sep, beg, end); ret << (rstr.isSharedWith(m_tmp1) ? str : ProString(rstr).setSource(str)); } @@ -516,7 +587,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( bool leftalign = false; enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign; if (args.count() >= 2) { - foreach (const ProString &opt, split_value_list(args.at(1).toQString(m_tmp2))) { + const auto opts = split_value_list(args.at(1).toQStringRef()); + for (const ProString &opt : opts) { opt.toQString(m_tmp3); if (m_tmp3.startsWith(QLatin1String("ibase="))) { ibase = m_tmp3.mid(6).toInt(); @@ -544,7 +616,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( break; } bool ok; - qlonglong num = m_tmp3.toLongLong(&ok, ibase); + qlonglong num = args.at(0).toLongLong(&ok, ibase); if (!ok) { evalError(fL1S("format_number(): malformed number %2 for base %1.") .arg(ibase).arg(m_tmp3)); @@ -575,14 +647,36 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( } formfail: break; + case E_NUM_ADD: + if (args.count() < 1 || args.at(0).isEmpty()) { + evalError(fL1S("num_add(num, ...) requires at least one argument.")); + } else { + qlonglong sum = 0; + foreach (const ProString &arg, args) { + if (arg.contains(QLatin1Char('.'))) { + evalError(fL1S("num_add(): floats are currently not supported.")); + goto nafail; + } + bool ok; + qlonglong num = arg.toLongLong(&ok); + if (!ok) { + evalError(fL1S("num_add(): malformed number %1.") + .arg(arg.toQString(m_tmp3))); + goto nafail; + } + sum += num; + } + ret += ProString(QString::number(sum)); + } + nafail: + break; case E_JOIN: { if (args.count() < 1 || args.count() > 4) { evalError(fL1S("join(var, glue, before, after) requires one to four arguments.")); } else { - QString glue; - ProString before, after; + ProString glue, before, after; if (args.count() >= 2) - glue = args.at(1).toQString(m_tmp1); + glue = args.at(1); if (args.count() >= 3) before = args[2]; if (args.count() == 4) @@ -590,7 +684,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( const ProStringList &var = values(map(args.at(0))); if (!var.isEmpty()) { const ProFile *src = currentProFile(); - foreach (const ProString &v, var) + for (const ProString &v : var) if (const ProFile *s = v.sourceFile()) { src = s; break; @@ -605,56 +699,49 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( evalError(fL1S("split(var, sep) requires one or two arguments.")); } else { const QString &sep = (args.count() == 2) ? args.at(1).toQString(m_tmp1) : statics.field_sep; - foreach (const ProString &var, values(map(args.at(0)))) - foreach (const QString &splt, var.toQString(m_tmp2).split(sep)) + const auto vars = values(map(args.at(0))); + for (const ProString &var : vars) { + const auto splits = var.toQString(m_tmp2).split(sep); + for (const QString &splt : splits) ret << (splt.isSharedWith(m_tmp2) ? var : ProString(splt).setSource(var)); + } } break; case E_MEMBER: if (args.count() < 1 || args.count() > 3) { evalError(fL1S("member(var, start, end) requires one to three arguments.")); } else { - bool ok = true; - const ProStringList &var = values(map(args.at(0))); - int start = 0, end = 0; - if (args.count() >= 2) { - const QString &start_str = args.at(1).toQString(m_tmp1); - start = start_str.toInt(&ok); - if (!ok) { - if (args.count() == 2) { - int dotdot = start_str.indexOf(statics.strDotDot); - if (dotdot != -1) { - start = start_str.left(dotdot).toInt(&ok); - if (ok) - end = start_str.mid(dotdot+2).toInt(&ok); - } - } - if (!ok) - evalError(fL1S("member() argument 2 (start) '%2' invalid.") - .arg(start_str)); + const ProStringList &src = values(map(args.at(0))); + int start, end; + if (getMemberArgs(func, src.size(), args, &start, &end)) { + ret.reserve(qAbs(end - start) + 1); + if (start < end) { + for (int i = start; i <= end && src.size() >= i; i++) + ret += src.at(i); } else { - end = start; - if (args.count() == 3) - end = args.at(2).toQString(m_tmp1).toInt(&ok); - if (!ok) - evalError(fL1S("member() argument 3 (end) '%2' invalid.") - .arg(args.at(2).toQString(m_tmp1))); + for (int i = start; i >= end && src.size() >= i && i >= 0; i--) + ret += src.at(i); } } - if (ok) { - if (start < 0) - start += var.count(); - if (end < 0) - end += var.count(); - if (start < 0 || start >= var.count() || end < 0 || end >= var.count()) { - //nothing - } else if (start < end) { - for (int i = start; i <= end && var.count() >= i; i++) - ret.append(var[i]); + } + break; + case E_STR_MEMBER: + if (args.count() < 1 || args.count() > 3) { + evalError(fL1S("str_member(str, start, end) requires one to three arguments.")); + } else { + const ProString &src = args.at(0); + int start, end; + if (getMemberArgs(func, src.size(), args, &start, &end)) { + QString res; + res.reserve(qAbs(end - start) + 1); + if (start < end) { + for (int i = start; i <= end && src.size() >= i; i++) + res += src.at(i); } else { - for (int i = start; i >= end && var.count() >= i && i >= 0; i--) - ret += var[i]; + for (int i = start; i >= end && src.size() >= i && i >= 0; i--) + res += src.at(i); } + ret += ProString(res); } } break; @@ -672,12 +759,32 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( } } break; + case E_TAKE_FIRST: + case E_TAKE_LAST: + if (args.count() != 1) { + evalError(fL1S("%1(var) requires one argument.").arg(func.toQString(m_tmp1))); + } else { + ProStringList &var = valuesRef(map(args.at(0))); + if (!var.isEmpty()) { + if (func_t == E_TAKE_FIRST) + ret.append(var.takeFirst()); + else + ret.append(var.takeLast()); + } + } + break; case E_SIZE: if (args.count() != 1) evalError(fL1S("size(var) requires one argument.")); else ret.append(ProString(QString::number(values(map(args.at(0))).size()))); break; + case E_STR_SIZE: + if (args.count() != 1) + evalError(fL1S("str_size(str) requires one argument.")); + else + ret.append(ProString(QString::number(args.at(0).size()))); + break; case E_CAT: if (args.count() < 1 || args.count() > 2) { evalError(fL1S("cat(file, singleline=true) requires one or two arguments.")); @@ -707,7 +814,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( if (lines) { ret += ProString(stream.readLine()); } else { - ret += split_value_list(stream.readLine().trimmed()); + const QString &line = stream.readLine(); + ret += split_value_list(QStringRef(&line).trimmed()); if (!singleLine) ret += ProString("\n"); } @@ -738,8 +846,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", m_listCount++); ret = ProStringList(ProString(tmp)); ProStringList lst; - foreach (const ProString &arg, args) - lst += split_value_list(arg.toQString(m_tmp1), arg.sourceFile()); // Relies on deep copy + for (const ProString &arg : args) + lst += split_value_list(arg.toQStringRef(), arg.sourceFile()); // Relies on deep copy m_valuemapStack.top()[ret.at(0).toKey()] = lst; break; } case E_FIND: @@ -748,7 +856,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( } else { QRegExp regx(args.at(1).toQString()); int t = 0; - foreach (const ProString &val, values(map(args.at(0)))) { + const auto vals = values(map(args.at(0))); + for (const ProString &val : vals) { if (regx.indexIn(val.toQString(m_tmp[t])) != -1) ret += val; t ^= 1; @@ -785,7 +894,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( output.replace(QLatin1Char('\t'), QLatin1Char(' ')); if (singleLine) output.replace(QLatin1Char('\n'), QLatin1Char(' ')); - ret += split_value_list(output); + ret += split_value_list(QStringRef(&output)); } } } @@ -799,6 +908,14 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( ret.removeDuplicates(); } break; + case E_SORTED: + if (args.count() != 1) { + evalError(fL1S("sorted(var) requires one argument.")); + } else { + ret = values(map(args.at(0))); + std::sort(ret.begin(), ret.end()); + } + break; case E_REVERSE: if (args.count() != 1) { evalError(fL1S("reverse(var) requires one argument.")); @@ -857,7 +974,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( } else { const ProStringList &vals = values(args.at(0).toKey()); ret.reserve(vals.size()); - foreach (const ProString &str, vals) + for (const ProString &str : vals) ret += ProString(quoteValue(str)); } break; @@ -882,7 +999,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( } else { bool recursive = false; if (args.count() == 2) - recursive = isTrue(args.at(1), m_tmp2); + recursive = isTrue(args.at(1)); QStringList dirs; QString r = m_option->expandEnvVars(args.at(0).toQString(m_tmp1)) .replace(QLatin1Char('\\'), QLatin1Char('/')); @@ -934,7 +1051,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( QFile qfile; if (qfile.open(stdin, QIODevice::ReadOnly)) { QTextStream t(&qfile); - ret = split_value_list(t.readLine()); + const QString &line = t.readLine(); + ret = split_value_list(QStringRef(&line)); } } break; } @@ -945,7 +1063,8 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( } else { const QRegExp before(args.at(1).toQString()); const QString &after(args.at(2).toQString(m_tmp2)); - foreach (const ProString &val, values(map(args.at(0)))) { + const auto vals = values(map(args.at(0))); + for (const ProString &val : vals) { QString rstr = val.toQString(m_tmp1); QString copy = rstr; // Force a detach on modify rstr.replace(before, after); @@ -967,7 +1086,7 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( ProString priosfx = args.count() < 4 ? ProString(".priority") : args.at(3); populateDeps(orgList, prefix, args.count() < 3 ? ProStringList(ProString(".depends")) - : split_value_list(args.at(2).toQString(m_tmp2)), + : split_value_list(args.at(2).toQStringRef()), priosfx, dependencies, dependees, rootSet); while (!rootSet.isEmpty()) { QMultiMap<int, ProString>::iterator it = rootSet.begin(); @@ -1010,7 +1129,11 @@ ProStringList QMakeEvaluator::evaluateBuiltinExpand( QString rstr = QDir::cleanPath( QDir(args.count() > 1 ? args.at(1).toQString(m_tmp2) : currentDirectory()) .absoluteFilePath(args.at(0).toQString(m_tmp1))); - ret << (rstr.isSharedWith(m_tmp1) ? args.at(0) : ProString(rstr).setSource(args.at(0))); + ret << (rstr.isSharedWith(m_tmp1) + ? args.at(0) + : args.count() > 1 && rstr.isSharedWith(m_tmp2) + ? args.at(1) + : ProString(rstr).setSource(args.at(0))); } break; case E_RELATIVE_PATH: @@ -1174,7 +1297,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( regx.setPattern(copy); } int t = 0; - foreach (const ProString &s, vars.value(map(args.at(1)))) { + const auto strings = vars.value(map(args.at(1))); + for (const ProString &s : strings) { if ((!regx.isEmpty() && regx.exactMatch(s.toQString(m_tmp[t]))) || s == qry) return ReturnTrue; t ^= 1; @@ -1183,12 +1307,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; case T_REQUIRES: #ifdef PROEVALUATOR_FULL - checkRequirements(args); + if (checkRequirements(args) == ReturnError) + return ReturnError; #endif return ReturnFalse; // Another qmake breakage case T_EVAL: { VisitReturn ret = ReturnFalse; - ProFile *pro = m_parser->parsedProBlock(args.join(statics.field_sep), + QString contents = args.join(statics.field_sep); + ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents), m_current.pro->fileName(), m_current.line); if (m_cumulative || pro->isOk()) { m_locationStack.push(m_current); @@ -1204,8 +1330,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( evalError(fL1S("if(condition) requires one argument.")); return ReturnFalse; } - return returnBool(evaluateConditional(args.at(0).toQString(), - m_current.pro->fileName(), m_current.line)); + return evaluateConditional(args.at(0).toQStringRef(), + m_current.pro->fileName(), m_current.line); } case T_CONFIG: { if (args.count() < 1 || args.count() > 2) { @@ -1268,7 +1394,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ReturnFalse; } int cnt = values(map(args.at(0))).count(); - int val = args.at(1).toQString(m_tmp1).toInt(); + int val = args.at(1).toInt(); if (args.count() == 3) { const ProString &comp = args.at(2); if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) { @@ -1377,7 +1503,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( flags = LoadSilent; if (args.count() >= 2) { parseInto = args.at(1).toQString(m_tmp2); - if (args.count() >= 3 && isTrue(args.at(2), m_tmp3)) + if (args.count() >= 3 && isTrue(args.at(2))) flags = LoadSilent; } QString fn = resolvePath(m_option->expandEnvVars(args.at(0).toQString(m_tmp1))); @@ -1415,7 +1541,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( case T_LOAD: { bool ignore_error = false; if (args.count() == 2) { - ignore_error = isTrue(args.at(1), m_tmp2); + ignore_error = isTrue(args.at(1)); } else if (args.count() != 1) { evalError(fL1S("load(feature) requires one or two arguments.")); return ReturnFalse; @@ -1480,9 +1606,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( runProcess(&proc, args.at(0).toQString(m_tmp2)); return returnBool(proc.exitStatus() == QProcess::NormalExit && proc.exitCode() == 0); #else - return returnBool(system((QLatin1String("cd ") - + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory())) - + QLatin1String(" && ") + args.at(0)).toLocal8Bit().constData()) == 0); + int ec = system((QLatin1String("cd ") + + IoUtils::shellQuote(QDir::toNativeSeparators(currentDirectory())) + + QLatin1String(" && ") + args.at(0)).toLocal8Bit().constData()); +# ifdef Q_OS_UNIX + if (ec != -1 && WIFSIGNALED(ec) && (WTERMSIG(ec) == SIGQUIT || WTERMSIG(ec) == SIGINT)) + raise(WTERMSIG(ec)); +# endif + return returnBool(ec == 0); #endif #else return ReturnTrue; @@ -1533,22 +1664,34 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } case T_WRITE_FILE: { if (args.count() > 3) { - evalError(fL1S("write_file(name, [content var, [append]]) requires one to three arguments.")); + evalError(fL1S("write_file(name, [content var, [append] [exe]]) requires one to three arguments.")); return ReturnFalse; } QIODevice::OpenMode mode = QIODevice::Truncate; + bool exe = false; QString contents; if (args.count() >= 2) { const ProStringList &vals = values(args.at(1).toKey()); if (!vals.isEmpty()) contents = vals.join(QLatin1Char('\n')) + QLatin1Char('\n'); - if (args.count() >= 3) - if (!args.at(2).toQString(m_tmp1).compare(fL1S("append"), Qt::CaseInsensitive)) - mode = QIODevice::Append; + if (args.count() >= 3) { + const auto opts = split_value_list(args.at(2).toQStringRef()); + for (const ProString &opt : opts) { + opt.toQString(m_tmp3); + if (m_tmp3 == QLatin1String("append")) { + mode = QIODevice::Append; + } else if (m_tmp3 == QLatin1String("exe")) { + exe = true; + } else { + evalError(fL1S("write_file(): invalid flag %1.").arg(m_tmp3)); + return ReturnFalse; + } + } + } } QString path = resolvePath(args.at(0).toQString(m_tmp1)); path.detach(); // make sure to not leak m_tmp1 into the map of written files. - return writeFile(QString(), path, mode, contents); + return writeFile(QString(), path, mode, exe, contents); } case T_TOUCH: { if (args.count() != 2) { @@ -1605,7 +1748,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet; ProKey srcvar; if (args.count() >= 2) { - foreach (const ProString &opt, split_value_list(args.at(1).toQString(m_tmp2))) { + const auto opts = split_value_list(args.at(1).toQStringRef()); + for (const ProString &opt : opts) { opt.toQString(m_tmp3); if (m_tmp3 == QLatin1String("transient")) { persist = false; @@ -1723,7 +1867,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( varstr += QLatin1Char(' '); varstr += quoteValue(diffval.at(0)); } else if (!diffval.isEmpty()) { - foreach (const ProString &vval, diffval) { + for (const ProString &vval : diffval) { varstr += QLatin1String(" \\\n "); varstr += quoteValue(vval); } @@ -1759,7 +1903,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( valuesRef(ProKey("_QMAKE_STASH_")) << ProString(fn); } } - return writeFile(fL1S("cache "), fn, QIODevice::Append, varstr); + return writeFile(fL1S("cache "), fn, QIODevice::Append, false, varstr); } default: evalError(fL1S("Function '%1' is not implemented.").arg(function.toQString(m_tmp1))); diff --git a/src/shared/proparser/qmakeevaluator.cpp b/src/shared/proparser/qmakeevaluator.cpp index dafb56244a..7d43610a31 100644 --- a/src/shared/proparser/qmakeevaluator.cpp +++ b/src/shared/proparser/qmakeevaluator.cpp @@ -183,6 +183,7 @@ void QMakeEvaluator::initStatics() { "IN_PWD", "PWD" }, { "DEPLOYMENT", "INSTALLS" } }; + statics.varMap.reserve((int)(sizeof(mapInits)/sizeof(mapInits[0]))); for (unsigned i = 0; i < sizeof(mapInits)/sizeof(mapInits[0]); ++i) statics.varMap.insert(ProKey(mapInits[i].oldname), ProKey(mapInits[i].newname)); } @@ -266,7 +267,7 @@ void QMakeEvaluator::skipHashStr(const ushort *&tokPtr) // FIXME: this should not build new strings for direct sections. // Note that the E_SPRINTF and E_LIST implementations rely on the deep copy. -ProStringList QMakeEvaluator::split_value_list(const QString &vals, const ProFile *source) +ProStringList QMakeEvaluator::split_value_list(const QStringRef &vals, const ProFile *source) { QString build; ProStringList ret; @@ -401,7 +402,7 @@ static ALWAYS_INLINE void addStrList( } } -void QMakeEvaluator::evaluateExpression( +QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpression( const ushort *&tokPtr, ProStringList *ret, bool joined) { debugMsg(2, joined ? "evaluating joined expression" : "evaluating expression"); @@ -451,12 +452,15 @@ void QMakeEvaluator::evaluateExpression( case TokFuncName: { const ProKey &func = pro->getHashStr(tokPtr); debugMsg(2, "function %s", dbgKey(func)); - addStrList(evaluateExpandFunction(func, tokPtr), tok, ret, pending, joined); + ProStringList val; + if (evaluateExpandFunction(func, tokPtr, &val) == ReturnError) + return ReturnError; + addStrList(val, tok, ret, pending, joined); break; } default: debugMsg(2, "evaluated expression => %s", dbgStrList(*ret)); tokPtr--; - return; + return ReturnTrue; } } } @@ -528,7 +532,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( case TokAppendUnique: case TokRemove: case TokReplace: - visitProVariable(tok, curr, tokPtr); + ret = visitProVariable(tok, curr, tokPtr); + if (ret == ReturnError) + break; curr.clear(); continue; case TokBranch: @@ -688,9 +694,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( continue; default: { const ushort *oTokPtr = --tokPtr; - evaluateExpression(tokPtr, &curr, false); - if (tokPtr != oTokPtr) - continue; + ret = evaluateExpression(tokPtr, &curr, false); + if (ret == ReturnError || tokPtr != oTokPtr) + break; } Q_ASSERT_X(false, "visitProBlock", "unexpected item type"); continue; @@ -723,7 +729,10 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( int index = 0; ProKey variable; ProStringList oldVarVal; - ProString it_list = expandVariableReferences(exprPtr, 0, true).at(0); + ProStringList it_list_out; + if (expandVariableReferences(exprPtr, 0, &it_list_out, true) == ReturnError) + return ReturnError; + ProString it_list = it_list_out.at(0); if (_variable.isEmpty()) { if (it_list != statics.strever) { evalError(fL1S("Invalid loop expression.")); @@ -752,12 +761,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( if (ok) { int end = itl.mid(dotdot+2).toInt(&ok); if (ok) { - if (m_cumulative && qAbs(end - start) > 100) { + const int absDiff = qAbs(end - start); + if (m_cumulative && absDiff > 100) { // Such a loop is unlikely to contribute something useful to the // file collection, and may cause considerable delay. traceMsg("skipping excessive loop in cumulative mode"); return ReturnFalse; } + list.reserve(absDiff + 1); if (start < end) { for (int i = start; i <= end; i++) list << ProString(QString::number(i)); @@ -820,7 +831,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( return ret; } -void QMakeEvaluator::visitProVariable( +QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( ushort tok, const ProStringList &curr, const ushort *&tokPtr) { int sizeHint = *tokPtr++; @@ -829,24 +840,26 @@ void QMakeEvaluator::visitProVariable( skipExpression(tokPtr); if (!m_cumulative || !curr.isEmpty()) evalError(fL1S("Left hand side of assignment must expand to exactly one word.")); - return; + return ReturnTrue; } const ProKey &varName = map(curr.first()); if (tok == TokReplace) { // ~= // DEFINES ~= s/a/b/?[gqi] - const ProStringList &varVal = expandVariableReferences(tokPtr, sizeHint, true); + ProStringList varVal; + if (expandVariableReferences(tokPtr, sizeHint, &varVal, true) == ReturnError) + return ReturnError; const QString &val = varVal.at(0).toQString(m_tmp1); if (val.length() < 4 || val.at(0) != QLatin1Char('s')) { evalError(fL1S("The ~= operator can handle only the s/// function.")); - return; + return ReturnTrue; } QChar sep = val.at(1); QStringList func = val.split(sep); if (func.count() < 3 || func.count() > 4) { evalError(fL1S("The s/// function expects 3 or 4 arguments.")); - return; + return ReturnTrue; } bool global = false, quote = false, case_sense = false; @@ -867,7 +880,9 @@ void QMakeEvaluator::visitProVariable( replaceInList(&valuesRef(varName), regexp, replace, global, m_tmp2); debugMsg(2, "replaced %s with %s", dbgQStr(pattern), dbgQStr(replace)); } else { - ProStringList varVal = expandVariableReferences(tokPtr, sizeHint); + ProStringList varVal; + if (expandVariableReferences(tokPtr, sizeHint, &varVal, false) == ReturnError) + return ReturnError; switch (tok) { default: // whatever - cannot happen case TokAssign: // = @@ -913,8 +928,10 @@ void QMakeEvaluator::visitProVariable( } #ifdef PROEVALUATOR_FULL else if (varName == statics.strREQUIRES) - checkRequirements(values(varName)); + return checkRequirements(values(varName)); #endif + + return ReturnTrue; } void QMakeEvaluator::setTemplate() @@ -949,7 +966,7 @@ static ProString msvcBinDirToQMakeArch(QString subdir) if (idx >= 0) subdir.remove(0, idx + 1); subdir = subdir.toLower(); - if (subdir == QStringLiteral("amd64")) + if (subdir == QLatin1String("amd64")) return ProString("x86_64"); return ProString(subdir); } @@ -970,7 +987,8 @@ static ProString msvcArchitecture(const QString &vcInstallDir, const QString &pa QString vcBinDir = vcInstallDir; if (vcBinDir.endsWith(QLatin1Char('\\'))) vcBinDir.chop(1); - foreach (const QString &dir, pathVar.split(QLatin1Char(';'))) { + const auto dirs = pathVar.split(QLatin1Char(';')); + for (const QString &dir : dirs) { if (!dir.startsWith(vcBinDir, Qt::CaseInsensitive)) continue; const ProString arch = msvcBinDirToQMakeArch(dir.mid(vcBinDir.length() + 1)); @@ -992,6 +1010,8 @@ void QMakeEvaluator::loadDefaults() vars[ProKey("QMAKE_QMAKE")] << ProString(m_option->qmake_abslocation); if (!m_option->qmake_args.isEmpty()) vars[ProKey("QMAKE_ARGS")] = ProStringList(m_option->qmake_args); + if (!m_option->qtconf.isEmpty()) + vars[ProKey("QMAKE_QTCONF")] = ProString(m_option->qtconf); vars[ProKey("QMAKE_HOST.cpu_count")] = ProString(QString::number(idealThreadCount())); #if defined(Q_OS_WIN32) vars[ProKey("QMAKE_HOST.os")] << ProString("Windows"); @@ -1268,7 +1288,7 @@ void QMakeEvaluator::setupProject() void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) { if (!cmds.isEmpty()) { - ProFile *pro = m_parser->parsedProBlock(cmds, where, -1); + ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), where, -1); if (pro->isOk()) { m_locationStack.push(m_current); visitProBlock(pro, pro->tokPtr()); @@ -1442,7 +1462,8 @@ void QMakeEvaluator::updateMkspecPaths() QStringList ret; const QString concat = QLatin1String("/mkspecs"); - foreach (const QString &it, m_option->getPathListEnv(QLatin1String("QMAKEPATH"))) + const auto paths = m_option->getPathListEnv(QLatin1String("QMAKEPATH")); + for (const QString &it : paths) ret << it + concat; foreach (const QString &it, m_qmakepath) @@ -1467,11 +1488,8 @@ void QMakeEvaluator::updateFeaturePaths() QStringList feature_roots; - foreach (const QString &f, m_option->getPathListEnv(QLatin1String("QMAKEFEATURES"))) - feature_roots += f; - + feature_roots += m_option->getPathListEnv(QLatin1String("QMAKEFEATURES")); feature_roots += m_qmakefeatures; - feature_roots += m_option->splitPathList( m_option->propertyValue(ProKey("QMAKEFEATURES")).toQString(m_mtmp)); @@ -1485,7 +1503,8 @@ void QMakeEvaluator::updateFeaturePaths() feature_bases << m_sourceRoot; } - foreach (const QString &item, m_option->getPathListEnv(QLatin1String("QMAKEPATH"))) + const auto items = m_option->getPathListEnv(QLatin1String("QMAKEPATH")); + for (const QString &item : items) feature_bases << (item + mkspecs_concat); foreach (const QString &item, m_qmakepath) @@ -1511,7 +1530,8 @@ void QMakeEvaluator::updateFeaturePaths() feature_bases << (m_option->propertyValue(ProKey("QT_HOST_DATA/src")) + mkspecs_concat); foreach (const QString &fb, feature_bases) { - foreach (const ProString &sfx, values(ProKey("QMAKE_PLATFORM"))) + const auto sfxs = values(ProKey("QMAKE_PLATFORM")); + for (const ProString &sfx : sfxs) feature_roots << (fb + features_concat + sfx + QLatin1Char('/')); feature_roots << (fb + features_concat); } @@ -1584,7 +1604,8 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex) // CONFIG variable int t = 0; - foreach (const ProString &configValue, values(statics.strCONFIG)) { + const auto configValues = values(statics.strCONFIG); + for (const ProString &configValue : configValues) { if (re.exactMatch(configValue.toQString(m_tmp[t]))) return true; t ^= 1; @@ -1602,18 +1623,18 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex) return false; } -ProStringList QMakeEvaluator::expandVariableReferences( - const ushort *&tokPtr, int sizeHint, bool joined) +QMakeEvaluator::VisitReturn QMakeEvaluator::expandVariableReferences( + const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined) { - ProStringList ret; - ret.reserve(sizeHint); + ret->reserve(sizeHint); forever { - evaluateExpression(tokPtr, &ret, joined); + if (evaluateExpression(tokPtr, ret, joined) == ReturnError) + return ReturnError; switch (*tokPtr) { case TokValueTerminator: case TokFuncTerminator: tokPtr++; - return ret; + return ReturnTrue; case TokArgSeparator: if (joined) { tokPtr++; @@ -1627,28 +1648,28 @@ ProStringList QMakeEvaluator::expandVariableReferences( } } -QList<ProStringList> QMakeEvaluator::prepareFunctionArgs(const ushort *&tokPtr) +QMakeEvaluator::VisitReturn QMakeEvaluator::prepareFunctionArgs( + const ushort *&tokPtr, QList<ProStringList> *ret) { - QList<ProStringList> args_list; if (*tokPtr != TokFuncTerminator) { for (;; tokPtr++) { ProStringList arg; - evaluateExpression(tokPtr, &arg, false); - args_list << arg; + if (evaluateExpression(tokPtr, &arg, false) == ReturnError) + return ReturnError; + *ret << arg; if (*tokPtr == TokFuncTerminator) break; Q_ASSERT(*tokPtr == TokArgSeparator); } } tokPtr++; - return args_list; + return ReturnTrue; } -ProStringList QMakeEvaluator::evaluateFunction( - const ProFunctionDef &func, const QList<ProStringList> &argumentsList, VisitReturn *ok) +QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFunction( + const ProFunctionDef &func, const QList<ProStringList> &argumentsList, ProStringList *ret) { VisitReturn vr; - ProStringList ret; if (m_valuemapStack.count() >= 100) { evalError(fL1S("Ran into infinite recursion (depth > 100).")); @@ -1667,25 +1688,22 @@ ProStringList QMakeEvaluator::evaluateFunction( vr = visitProBlock(func.pro(), func.tokPtr()); if (vr == ReturnReturn) vr = ReturnTrue; - ret = m_returnValue; + if (vr == ReturnTrue) + *ret = m_returnValue; m_returnValue.clear(); m_current = m_locationStack.pop(); m_valuemapStack.pop(); } - if (ok) - *ok = vr; - if (vr == ReturnTrue) - return ret; - return ProStringList(); + return vr; } QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBoolFunction( const ProFunctionDef &func, const QList<ProStringList> &argumentsList, const ProString &function) { - VisitReturn vr; - ProStringList ret = evaluateFunction(func, argumentsList, &vr); + ProStringList ret; + VisitReturn vr = evaluateFunction(func, argumentsList, &ret); if (vr == ReturnTrue) { if (ret.isEmpty()) return ReturnTrue; @@ -1713,13 +1731,18 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction( { if (int func_t = statics.functions.value(func)) { //why don't the builtin functions just use args_list? --Sam - return evaluateBuiltinConditional(func_t, func, expandVariableReferences(tokPtr, 5, true)); + ProStringList args; + if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError) + return ReturnError; + return evaluateBuiltinConditional(func_t, func, args); } QHash<ProKey, ProFunctionDef>::ConstIterator it = m_functionDefs.testFunctions.constFind(func); if (it != m_functionDefs.testFunctions.constEnd()) { - const QList<ProStringList> args = prepareFunctionArgs(tokPtr); + QList<ProStringList> args; + if (prepareFunctionArgs(tokPtr, &args) == ReturnError) + return ReturnError; traceMsg("calling %s(%s)", dbgKey(func), dbgStrListList(args)); return evaluateBoolFunction(*it, args, func); } @@ -1729,34 +1752,41 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditionalFunction( return ReturnFalse; } -ProStringList QMakeEvaluator::evaluateExpandFunction( - const ProKey &func, const ushort *&tokPtr) +QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpandFunction( + const ProKey &func, const ushort *&tokPtr, ProStringList *ret) { if (int func_t = statics.expands.value(func)) { //why don't the builtin functions just use args_list? --Sam - return evaluateBuiltinExpand(func_t, func, expandVariableReferences(tokPtr, 5, true)); + ProStringList args; + if (expandVariableReferences(tokPtr, 5, &args, true) == ReturnError) + return ReturnError; + *ret = evaluateBuiltinExpand(func_t, func, args); + return ReturnTrue; } QHash<ProKey, ProFunctionDef>::ConstIterator it = m_functionDefs.replaceFunctions.constFind(func); if (it != m_functionDefs.replaceFunctions.constEnd()) { - const QList<ProStringList> args = prepareFunctionArgs(tokPtr); + QList<ProStringList> args; + if (prepareFunctionArgs(tokPtr, &args) == ReturnError) + return ReturnError; traceMsg("calling $$%s(%s)", dbgKey(func), dbgStrListList(args)); - return evaluateFunction(*it, args, 0); + return evaluateFunction(*it, args, ret); } skipExpression(tokPtr); evalError(fL1S("'%1' is not a recognized replace function.").arg(func.toQString(m_tmp1))); - return ProStringList(); + return ReturnFalse; } -bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &where, int line) +QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional( + const QStringRef &cond, const QString &where, int line) { - bool ret = false; + VisitReturn ret = ReturnFalse; ProFile *pro = m_parser->parsedProBlock(cond, where, line, QMakeParser::TestGrammar); if (pro->isOk()) { m_locationStack.push(m_current); - ret = visitProBlock(pro, pro->tokPtr()) == ReturnTrue; + ret = visitProBlock(pro, pro->tokPtr()); m_current = m_locationStack.pop(); } pro->deref(); @@ -1764,28 +1794,49 @@ bool QMakeEvaluator::evaluateConditional(const QString &cond, const QString &whe } #ifdef PROEVALUATOR_FULL -void QMakeEvaluator::checkRequirements(const ProStringList &deps) +QMakeEvaluator::VisitReturn QMakeEvaluator::checkRequirements(const ProStringList &deps) { ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS")); - foreach (const ProString &dep, deps) - if (!evaluateConditional(dep.toQString(), m_current.pro->fileName(), m_current.line)) + for (const ProString &dep : deps) { + VisitReturn vr = evaluateConditional(dep.toQStringRef(), m_current.pro->fileName(), m_current.line); + if (vr == ReturnError) + return ReturnError; + if (vr != ReturnTrue) failed << dep; + } + return ReturnTrue; } #endif +static bool isFunctParam(const ProKey &variableName) +{ + const int len = variableName.size(); + const QChar *data = variableName.constData(); + for (int i = 0; i < len; i++) { + ushort c = data[i].unicode(); + if (c < '0' || c > '9') + return false; + } + return true; +} + ProValueMap *QMakeEvaluator::findValues(const ProKey &variableName, ProValueMap::Iterator *rit) { ProValueMapStack::Iterator vmi = m_valuemapStack.end(); - do { + for (bool first = true; ; first = false) { --vmi; ProValueMap::Iterator it = (*vmi).find(variableName); if (it != (*vmi).end()) { if (it->constBegin() == statics.fakeValue.constBegin()) - return 0; + break; *rit = it; return &(*vmi); } - } while (vmi != m_valuemapStack.begin()); + if (vmi == m_valuemapStack.begin()) + break; + if (first && isFunctParam(variableName)) + break; + } return 0; } @@ -1797,18 +1848,20 @@ ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName) it->clear(); return *it; } - ProValueMapStack::Iterator vmi = m_valuemapStack.end(); - if (--vmi != m_valuemapStack.begin()) { - do { - --vmi; - ProValueMap::ConstIterator it = (*vmi).constFind(variableName); - if (it != (*vmi).constEnd()) { - ProStringList &ret = m_valuemapStack.top()[variableName]; - if (it->constBegin() != statics.fakeValue.constBegin()) - ret = *it; - return ret; - } - } while (vmi != m_valuemapStack.begin()); + if (!isFunctParam(variableName)) { + ProValueMapStack::Iterator vmi = m_valuemapStack.end(); + if (--vmi != m_valuemapStack.begin()) { + do { + --vmi; + ProValueMap::ConstIterator it = (*vmi).constFind(variableName); + if (it != (*vmi).constEnd()) { + ProStringList &ret = m_valuemapStack.top()[variableName]; + if (it->constBegin() != statics.fakeValue.constBegin()) + ret = *it; + return ret; + } + } while (vmi != m_valuemapStack.begin()); + } } return m_valuemapStack.top()[variableName]; } @@ -1816,7 +1869,7 @@ ProStringList &QMakeEvaluator::valuesRef(const ProKey &variableName) ProStringList QMakeEvaluator::values(const ProKey &variableName) const { ProValueMapStack::ConstIterator vmi = m_valuemapStack.constEnd(); - do { + for (bool first = true; ; first = false) { --vmi; ProValueMap::ConstIterator it = (*vmi).constFind(variableName); if (it != (*vmi).constEnd()) { @@ -1824,7 +1877,11 @@ ProStringList QMakeEvaluator::values(const ProKey &variableName) const break; return *it; } - } while (vmi != m_valuemapStack.constBegin()); + if (vmi == m_valuemapStack.constBegin()) + break; + if (first && isFunctParam(variableName)) + break; + } return ProStringList(); } @@ -1864,9 +1921,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFileChecked( { if (fileName.isEmpty()) return ReturnFalse; - QMakeEvaluator *ref = this; + const QMakeEvaluator *ref = this; do { - foreach (const ProFile *pf, ref->m_profileStack) + for (const ProFile *pf : ref->m_profileStack) if (pf->fileName() == fileName) { evalError(fL1S("Circular inclusion of %1.").arg(fileName)); return ReturnFalse; @@ -1967,7 +2024,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFileInto( *values = visitor.m_valuemapStack.top(); ProKey qiif("QMAKE_INTERNAL_INCLUDED_FILES"); ProStringList &iif = m_valuemapStack.first()[qiif]; - foreach (const ProString &ifn, values->value(qiif)) + const auto ifns = values->value(qiif); + for (const ProString &ifn : ifns) if (!iif.contains(ifn)) iif << ifn; return ReturnTrue; @@ -2066,7 +2124,7 @@ QString QMakeEvaluator::formatValueList(const ProStringList &vals, bool commas) { QString ret; - foreach (const ProString &str, vals) { + for (const ProString &str : vals) { if (!ret.isEmpty()) { if (commas) ret += QLatin1Char(','); @@ -2081,7 +2139,7 @@ QString QMakeEvaluator::formatValueListList(const QList<ProStringList> &lists) { QString ret; - foreach (const ProStringList &list, lists) { + for (const ProStringList &list : lists) { if (!ret.isEmpty()) ret += QLatin1String(", "); ret += formatValueList(list); diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h index 7bb673cb89..e9cff77c67 100644 --- a/src/shared/proparser/qmakeevaluator.h +++ b/src/shared/proparser/qmakeevaluator.h @@ -144,7 +144,7 @@ public: { return b ? ReturnTrue : ReturnFalse; } static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr); - void evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined); + VisitReturn evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined); static ALWAYS_INLINE void skipStr(const ushort *&tokPtr); static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr); void skipExpression(const ushort *&tokPtr); @@ -164,7 +164,7 @@ public: VisitReturn visitProLoop(const ProKey &variable, const ushort *exprPtr, const ushort *tokPtr); void visitProFunctionDef(ushort tok, const ProKey &name, const ushort *tokPtr); - void visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr); + VisitReturn visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr); ALWAYS_INLINE const ProKey &map(const ProString &var) { return map(var.toKey()); } const ProKey &map(const ProKey &var); @@ -172,9 +172,8 @@ public: void setTemplate(); - ProStringList split_value_list(const QString &vals, const ProFile *source = 0); - ProStringList expandVariableReferences(const ProString &value, int *pos = 0, bool joined = false); - ProStringList expandVariableReferences(const ushort *&tokPtr, int sizeHint = 0, bool joined = false); + ProStringList split_value_list(const QStringRef &vals, const ProFile *source = 0); + VisitReturn expandVariableReferences(const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined); QString currentFileName() const; QString currentDirectory() const; @@ -199,22 +198,22 @@ public: void deprecationWarning(const QString &msg) const { message(QMakeHandler::EvalWarnDeprecated, msg); } - QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr); - ProStringList evaluateFunction(const ProFunctionDef &func, - const QList<ProStringList> &argumentsList, VisitReturn *ok); + VisitReturn prepareFunctionArgs(const ushort *&tokPtr, QList<ProStringList> *ret); + VisitReturn evaluateFunction(const ProFunctionDef &func, + const QList<ProStringList> &argumentsList, ProStringList *ret); VisitReturn evaluateBoolFunction(const ProFunctionDef &func, const QList<ProStringList> &argumentsList, const ProString &function); - ProStringList evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr); + VisitReturn evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr, ProStringList *ret); VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr); ProStringList evaluateBuiltinExpand(int func_t, const ProKey &function, const ProStringList &args); VisitReturn evaluateBuiltinConditional(int func_t, const ProKey &function, const ProStringList &args); - bool evaluateConditional(const QString &cond, const QString &where, int line = -1); + VisitReturn evaluateConditional(const QStringRef &cond, const QString &where, int line = -1); #ifdef PROEVALUATOR_FULL - void checkRequirements(const ProStringList &deps); + VisitReturn checkRequirements(const ProStringList &deps); #endif void updateMkspecPaths(); @@ -228,8 +227,12 @@ public: QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees, QMultiMap<int, ProString> &rootSet) const; + bool getMemberArgs(const ProKey &name, int srclen, const ProStringList &args, + int *start, int *end); + VisitReturn parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value); + VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode, - const QString &contents); + bool exe, const QString &contents); #ifndef QT_BOOTSTRAPPED void runProcess(QProcess *proc, const QString &command) const; #endif diff --git a/src/shared/proparser/qmakeglobals.cpp b/src/shared/proparser/qmakeglobals.cpp index 2231391f9a..f3600b33e0 100644 --- a/src/shared/proparser/qmakeglobals.cpp +++ b/src/shared/proparser/qmakeglobals.cpp @@ -56,9 +56,11 @@ #ifdef Q_OS_WIN32 #define QT_POPEN _popen +#define QT_POPEN_READ "rb" #define QT_PCLOSE _pclose #else #define QT_POPEN popen +#define QT_POPEN_READ "r" #define QT_PCLOSE pclose #endif @@ -101,7 +103,7 @@ QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &s QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( QMakeCmdLineParserState &state, QStringList &args, int *pos) { - enum { ArgNone, ArgConfig, ArgSpec, ArgXSpec, ArgTmpl, ArgTmplPfx, ArgCache } argState = ArgNone; + enum { ArgNone, ArgConfig, ArgSpec, ArgXSpec, ArgTmpl, ArgTmplPfx, ArgCache, ArgQtConf } argState = ArgNone; for (; *pos < args.count(); (*pos)++) { QString arg = args.at(*pos); switch (argState) { @@ -126,8 +128,16 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( case ArgCache: cachefile = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg)); break; + case ArgQtConf: + qtconf = args[*pos] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg)); + break; default: if (arg.startsWith(QLatin1Char('-'))) { + if (arg == QLatin1String("--")) { + state.extraargs = args.mid(*pos + 1); + *pos = args.size(); + return ArgumentsOk; + } if (arg == QLatin1String("-after")) state.after = true; else if (arg == QLatin1String("-config")) @@ -136,6 +146,8 @@ QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments( do_cache = false; else if (arg == QLatin1String("-cache")) argState = ArgCache; + else if (arg == QLatin1String("-qtconf")) + argState = ArgQtConf; else if (arg == QLatin1String("-platform") || arg == QLatin1String("-spec")) argState = ArgSpec; else if (arg == QLatin1String("-xplatform") || arg == QLatin1String("-xspec")) @@ -171,6 +183,12 @@ void QMakeGlobals::commitCommandLineArguments(QMakeCmdLineParserState &state) { if (!state.preconfigs.isEmpty()) state.precmds << (fL1S("CONFIG += ") + state.preconfigs.join(QLatin1Char(' '))); + if (!state.extraargs.isEmpty()) { + QString extra = fL1S("QMAKE_EXTRA_ARGS ="); + foreach (const QString &ea, state.extraargs) + extra += QLatin1Char(' ') + QMakeEvaluator::quoteValue(ProString(ea)); + state.precmds << extra; + } precmds = state.precmds.join(QLatin1Char('\n')); if (!state.postconfigs.isEmpty()) state.postcmds << (fL1S("CONFIG += ") + state.postconfigs.join(QLatin1Char(' '))); @@ -240,9 +258,9 @@ QStringList QMakeGlobals::splitPathList(const QString &val) const QStringList ret; if (!val.isEmpty()) { QDir bdir; - QStringList vals = val.split(dirlist_sep); + const QStringList vals = val.split(dirlist_sep); ret.reserve(vals.length()); - foreach (const QString &it, vals) + for (const QString &it : vals) ret << QDir::cleanPath(bdir.absoluteFilePath(it)); } return ret; @@ -299,14 +317,15 @@ bool QMakeGlobals::initProperties() data = proc.readAll(); #else if (FILE *proc = QT_POPEN(QString(QMakeInternal::IoUtils::shellQuote(qmake_abslocation) - + QLatin1String(" -query")).toLocal8Bit(), "r")) { + + QLatin1String(" -query")).toLocal8Bit(), QT_POPEN_READ)) { char buff[1024]; while (!feof(proc)) data.append(buff, int(fread(buff, 1, 1023, proc))); QT_PCLOSE(proc); } #endif - foreach (QByteArray line, data.split('\n')) { + const auto lines = data.split('\n'); + for (QByteArray line : lines) { int off = line.indexOf(':'); if (off < 0) // huh? continue; diff --git a/src/shared/proparser/qmakeglobals.h b/src/shared/proparser/qmakeglobals.h index 33a5bdb831..9942113681 100644 --- a/src/shared/proparser/qmakeglobals.h +++ b/src/shared/proparser/qmakeglobals.h @@ -81,7 +81,7 @@ class QMAKE_EXPORT QMakeCmdLineParserState public: QMakeCmdLineParserState(const QString &_pwd) : pwd(_pwd), after(false) {} QString pwd; - QStringList precmds, preconfigs, postcmds, postconfigs; + QStringList precmds, preconfigs, postcmds, postconfigs, extraargs; bool after; void flush() { after = false; } @@ -103,6 +103,7 @@ public: QString qmake_abslocation; QStringList qmake_args; + QString qtconf; QString qmakespec, xqmakespec; QString user_template, user_template_prefix; QString precmds, postcmds; diff --git a/src/shared/proparser/qmakeparser.cpp b/src/shared/proparser/qmakeparser.cpp index 59dc289548..7751265e91 100644 --- a/src/shared/proparser/qmakeparser.cpp +++ b/src/shared/proparser/qmakeparser.cpp @@ -221,7 +221,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) } ProFile *QMakeParser::parsedProBlock( - const QString &contents, const QString &name, int line, SubGrammar grammar) + const QStringRef &contents, const QString &name, int line, SubGrammar grammar) { ProFile *pro = new ProFile(name); read(pro, contents, line, grammar); @@ -244,7 +244,7 @@ bool QMakeParser::read(ProFile *pro, ParseFlags flags) fL1S("Cannot read %1: %2").arg(pro->fileName(), errStr)); return false; } - read(pro, content, 1, FullGrammar); + read(pro, QStringRef(&content), 1, FullGrammar); return true; } @@ -272,7 +272,8 @@ void QMakeParser::putHashStr(ushort *&pTokPtr, const ushort *buf, uint len) *tokPtr++ = (ushort)hash; *tokPtr++ = (ushort)(hash >> 16); *tokPtr++ = (ushort)len; - memcpy(tokPtr, buf, len * 2); + if (len) // buf may be nullptr; don't pass that to memcpy (-> undefined behavior) + memcpy(tokPtr, buf, len * 2); pTokPtr = tokPtr + len; } @@ -285,7 +286,7 @@ void QMakeParser::finalizeHashStr(ushort *buf, uint len) buf[-2] = (ushort)(hash >> 16); } -void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar grammar) +void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar grammar) { m_proFile = pro; m_lineNo = line; @@ -295,27 +296,30 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra // Worst-case size calculations: // - line marker adds 1 (2-nl) to 1st token of each line // - empty assignment "A=":2 => - // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + 0(1) + + // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + size_hint(1) + // TokValueTerminator(1) == 8 (9) // - non-empty assignment "A=B C":5 => - // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + 2(1) + + // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokAssign(1) + size_hint(1) + // TokLiteral(1) + len(1) + "B"(1) + // TokLiteral(1) + len(1) + "C"(1) + TokValueTerminator(1) == 14 (15) // - variable expansion: "$$f":3 => // TokVariable(1) + hash(2) + len(1) + "f"(1) = 5 // - function expansion: "$$f()":5 => // TokFuncName(1) + hash(2) + len(1) + "f"(1) + TokFuncTerminator(1) = 6 + // - test literal: "X":1 => + // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokCondition(1) = 6 (7) // - scope: "X:":2 => // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokCondition(1) + - // TokBranch(1) + len(2) + ... + len(2) + ... == 10 - // - test: "X():":4 => + // TokBranch(1) + len(2) + ... + len(2) + ... == 11 (12) + // - test call: "X():":4 => // TokHashLiteral(1) + hash(2) + len(1) + "A"(1) + TokTestCall(1) + TokFuncTerminator(1) + - // TokBranch(1) + len(2) + ... + len(2) + ... == 11 + // TokBranch(1) + len(2) + ... + len(2) + ... == 12 (13) // - "for(A,B):":9 => // TokForLoop(1) + hash(2) + len(1) + "A"(1) + // len(2) + TokLiteral(1) + len(1) + "B"(1) + TokValueTerminator(1) + // len(2) + ... + TokTerminator(1) == 14 (15) - tokBuff.reserve((in.size() + 1) * 5); + // One extra for possibly missing trailing newline. + tokBuff.reserve((in.size() + 1) * 7); ushort *tokPtr = (ushort *)tokBuff.constData(); // Current writing position // Expression precompiler buffer. @@ -330,8 +334,8 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra QStack<ParseCtx> xprStack; xprStack.reserve(10); - // We rely on QStrings being null-terminated, so don't maintain a global end pointer. const ushort *cur = (const ushort *)in.unicode(); + const ushort *inend = cur + in.length(); m_canElse = false; freshLine: m_state = StNew; @@ -414,7 +418,7 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra int indent; if (context == CtxPureValue) { - end = (const ushort *)in.unicode() + in.length(); + end = inend; cptr = 0; lineCont = false; indent = 0; // just gcc being stupid @@ -426,24 +430,30 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra // First, skip leading whitespace for (indent = 0; ; ++cur, ++indent) { + if (cur == inend) { + cur = 0; + goto flushLine; + } c = *cur; if (c == '\n') { ++cur; goto flushLine; - } else if (!c) { - cur = 0; - goto flushLine; - } else if (c != ' ' && c != '\t' && c != '\r') { - break; } + if (c != ' ' && c != '\t' && c != '\r') + break; } // Then strip comments. Yep - no escaping is possible. for (cptr = cur;; ++cptr) { + if (cptr == inend) { + end = cptr; + break; + } c = *cptr; if (c == '#') { - for (end = cptr; (c = *++cptr);) { - if (c == '\n') { + end = cptr; + while (++cptr < inend) { + if (*cptr == '\n') { ++cptr; break; } @@ -456,10 +466,6 @@ void QMakeParser::read(ProFile *pro, const QString &in, int line, SubGrammar gra } break; } - if (!c) { - end = cptr; - break; - } if (c == '\n') { end = cptr++; break; @@ -1211,7 +1217,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg bool QMakeParser::resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr, ushort **buf, QString *xprBuff, ushort **tokPtr, QString *tokBuff, - const ushort *cur, const QString &in) + const ushort *cur, const QStringRef &in) { QString out; m_tmp.setRawData((const QChar *)xprPtr, tlen); diff --git a/src/shared/proparser/qmakeparser.h b/src/shared/proparser/qmakeparser.h index d44523d024..d370d17cbb 100644 --- a/src/shared/proparser/qmakeparser.h +++ b/src/shared/proparser/qmakeparser.h @@ -83,7 +83,7 @@ public: enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar }; // fileName is expected to be absolute and cleanPath()ed. ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault); - ProFile *parsedProBlock(const QString &contents, const QString &name, int line = 0, + ProFile *parsedProBlock(const QStringRef &contents, const QString &name, int line = 0, SubGrammar grammar = FullGrammar); void discardFileFromCache(const QString &fileName); @@ -126,7 +126,7 @@ private: }; bool read(ProFile *pro, ParseFlags flags); - void read(ProFile *pro, const QString &content, int line, SubGrammar grammar); + void read(ProFile *pro, const QStringRef &content, int line, SubGrammar grammar); ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok); ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len); @@ -137,7 +137,7 @@ private: ALWAYS_INLINE bool resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr, ushort **buf, QString *xprBuff, ushort **tokPtr, QString *tokBuff, - const ushort *cur, const QString &in); + const ushort *cur, const QStringRef &in); void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount); void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc); void warnOperator(const char *msg); diff --git a/src/shared/proparser/qmakevfs.cpp b/src/shared/proparser/qmakevfs.cpp index 7eb35bebca..0231fa9a46 100644 --- a/src/shared/proparser/qmakevfs.cpp +++ b/src/shared/proparser/qmakevfs.cpp @@ -44,8 +44,8 @@ QMakeVfs::QMakeVfs() { } -bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents, - QString *errStr) +bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, bool exe, + const QString &contents, QString *errStr) { #ifndef PROEVALUATOR_FULL # ifdef PROEVALUATOR_THREAD_SAFE @@ -57,6 +57,7 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QStr else *cont = contents; Q_UNUSED(errStr) + Q_UNUSED(exe) return true; #else QFileInfo qfi(fn); @@ -67,8 +68,16 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QStr QByteArray bytes = contents.toLocal8Bit(); QFile cfile(fn); if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) { - if (cfile.readAll() == bytes) + if (cfile.readAll() == bytes) { + if (exe) { + cfile.setPermissions(cfile.permissions() + | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther); + } else { + cfile.setPermissions(cfile.permissions() + & ~(QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther)); + } return true; + } cfile.close(); } if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) { @@ -81,6 +90,9 @@ bool QMakeVfs::writeFile(const QString &fn, QIODevice::OpenMode mode, const QStr *errStr = cfile.errorString(); return false; } + if (exe) + cfile.setPermissions(cfile.permissions() + | QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther); return true; #endif } diff --git a/src/shared/proparser/qmakevfs.h b/src/shared/proparser/qmakevfs.h index 8c387fe29d..3ffe67c1ba 100644 --- a/src/shared/proparser/qmakevfs.h +++ b/src/shared/proparser/qmakevfs.h @@ -43,7 +43,7 @@ class QMAKE_EXPORT QMakeVfs public: QMakeVfs(); - bool writeFile(const QString &fn, QIODevice::OpenMode mode, const QString &contents, QString *errStr); + bool writeFile(const QString &fn, QIODevice::OpenMode mode, bool exe, const QString &contents, QString *errStr); bool readFile(const QString &fn, QString *contents, QString *errStr); bool exists(const QString &fn); diff --git a/src/shared/qbs b/src/shared/qbs -Subproject 65cb4cba999b47a643e820a102b3185f861b97c +Subproject a3466fc55fb7756fcc9ddd6aeabbdef80c0108e |