From 92ec21e5b5d89680f169f9f48cf99d891e63d3dc Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 10 Jan 2018 14:32:21 +0100 Subject: [PATCH 01/16] Core: add menu bar locator filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding the possibility to trigger menu actions from the locator Change-Id: I70d595c167f5b43b02f8125eafbb83e5b45012c9 Reviewed-by: André Hartmann Reviewed-by: Eike Ziller --- src/plugins/coreplugin/coreplugin.cpp | 9 +- src/plugins/coreplugin/coreplugin.pro | 6 +- src/plugins/coreplugin/coreplugin.qbs | 211 +++++++++++++++-------- src/plugins/coreplugin/menubarfilter.cpp | 162 +++++++++++++++++ src/plugins/coreplugin/menubarfilter.h | 58 +++++++ 5 files changed, 373 insertions(+), 73 deletions(-) create mode 100644 src/plugins/coreplugin/menubarfilter.cpp create mode 100644 src/plugins/coreplugin/menubarfilter.h diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 65fba9709f9..577a9f9487b 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -26,12 +26,13 @@ #include "coreplugin.h" #include "designmode.h" #include "editmode.h" -#include "idocument.h" #include "helpmanager.h" -#include "mainwindow.h" -#include "modemanager.h" +#include "idocument.h" #include "infobar.h" #include "iwizardfactory.h" +#include "mainwindow.h" +#include "menubarfilter.h" +#include "modemanager.h" #include "reaper_p.h" #include "themechooser.h" @@ -162,6 +163,8 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) InfoBar::initialize(ICore::settings(), creatorTheme()); } + addAutoReleasedObject(new MenuBarFilter); + IWizardFactory::initialize(); // Make sure we respect the process's umask when creating new files diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro index dd6f03bdaa7..d5f1f7f51ed 100644 --- a/src/plugins/coreplugin/coreplugin.pro +++ b/src/plugins/coreplugin/coreplugin.pro @@ -111,7 +111,8 @@ SOURCES += corejsextensions.cpp \ externaltoolmanager.cpp \ systemsettings.cpp \ coreicons.cpp \ - diffservice.cpp + diffservice.cpp \ + menubarfilter.cpp HEADERS += corejsextensions.h \ mainwindow.h \ @@ -222,7 +223,8 @@ HEADERS += corejsextensions.h \ systemsettings.h \ coreicons.h \ editormanager/documentmodel_p.h \ - diffservice.h + diffservice.h \ + menubarfilter.h FORMS += dialogs/newdialog.ui \ dialogs/saveitemsdialog.ui \ diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index eabf668df71..109993bb115 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -32,79 +32,154 @@ Project { Group { name: "General" files: [ - "basefilewizard.cpp", "basefilewizard.h", - "basefilewizardfactory.cpp", "basefilewizardfactory.h", + "basefilewizard.cpp", + "basefilewizard.h", + "basefilewizardfactory.cpp", + "basefilewizardfactory.h", "core.qrc", "core_global.h", "coreconstants.h", - "coreicons.cpp", "coreicons.h", - "corejsextensions.cpp", "corejsextensions.h", - "coreplugin.cpp", "coreplugin.h", - "designmode.cpp", "designmode.h", - "diffservice.cpp", "diffservice.h", - "documentmanager.cpp", "documentmanager.h", - "editmode.cpp", "editmode.h", - "editortoolbar.cpp", "editortoolbar.h", - "externaltool.cpp", "externaltool.h", - "externaltoolmanager.cpp", "externaltoolmanager.h", - "fancyactionbar.cpp", "fancyactionbar.h", "fancyactionbar.qrc", - "fancytabwidget.cpp", "fancytabwidget.h", - "featureprovider.cpp", "featureprovider.h", - "fileiconprovider.cpp", "fileiconprovider.h", - "fileutils.cpp", "fileutils.h", - "findplaceholder.cpp", "findplaceholder.h", - "generalsettings.cpp", "generalsettings.h", "generalsettings.ui", - "generatedfile.cpp", "generatedfile.h", - "helpmanager.cpp", "helpmanager.h", - "icontext.cpp", "icontext.h", - "icore.cpp", "icore.h", - "id.cpp", "id.h", - "idocument.cpp", "idocument.h", - "idocumentfactory.cpp", "idocumentfactory.h", + "coreicons.cpp", + "coreicons.h", + "corejsextensions.cpp", + "corejsextensions.h", + "coreplugin.cpp", + "coreplugin.h", + "designmode.cpp", + "designmode.h", + "diffservice.cpp", + "diffservice.h", + "documentmanager.cpp", + "documentmanager.h", + "editmode.cpp", + "editmode.h", + "editortoolbar.cpp", + "editortoolbar.h", + "externaltool.cpp", + "externaltool.h", + "externaltoolmanager.cpp", + "externaltoolmanager.h", + "fancyactionbar.cpp", + "fancyactionbar.h", + "fancyactionbar.qrc", + "fancytabwidget.cpp", + "fancytabwidget.h", + "featureprovider.cpp", + "featureprovider.h", + "fileiconprovider.cpp", + "fileiconprovider.h", + "fileutils.cpp", + "fileutils.h", + "findplaceholder.cpp", + "findplaceholder.h", + "generalsettings.cpp", + "generalsettings.h", + "generalsettings.ui", + "generatedfile.cpp", + "generatedfile.h", + "helpmanager.cpp", + "helpmanager.h", + "icontext.cpp", + "icontext.h", + "icore.cpp", + "icore.h", + "id.cpp", + "id.h", + "idocument.cpp", + "idocument.h", + "idocumentfactory.cpp", + "idocumentfactory.h", "ifilewizardextension.h", - "imode.cpp", "imode.h", - "inavigationwidgetfactory.cpp", "inavigationwidgetfactory.h", - "infobar.cpp", "infobar.h", - "ioutputpane.cpp", "ioutputpane.h", - "iversioncontrol.cpp", "iversioncontrol.h", - "iwelcomepage.cpp", "iwelcomepage.h", - "iwizardfactory.cpp", "iwizardfactory.h", - "jsexpander.cpp", "jsexpander.h", - "mainwindow.cpp", "mainwindow.h", - "manhattanstyle.cpp", "manhattanstyle.h", - "messagebox.cpp", "messagebox.h", - "messagemanager.cpp", "messagemanager.h", - "messageoutputwindow.cpp", "messageoutputwindow.h", - "mimetypemagicdialog.cpp", "mimetypemagicdialog.h", "mimetypemagicdialog.ui", - "mimetypesettings.cpp", "mimetypesettings.h", + "imode.cpp", + "imode.h", + "inavigationwidgetfactory.cpp", + "inavigationwidgetfactory.h", + "infobar.cpp", + "infobar.h", + "ioutputpane.cpp", + "ioutputpane.h", + "iversioncontrol.cpp", + "iversioncontrol.h", + "iwelcomepage.cpp", + "iwelcomepage.h", + "iwizardfactory.cpp", + "iwizardfactory.h", + "jsexpander.cpp", + "jsexpander.h", + "mainwindow.cpp", + "mainwindow.h", + "manhattanstyle.cpp", + "manhattanstyle.h", + "menubarfilter.cpp", + "menubarfilter.h", + "messagebox.cpp", + "messagebox.h", + "messagemanager.cpp", + "messagemanager.h", + "messageoutputwindow.cpp", + "messageoutputwindow.h", + "mimetypemagicdialog.cpp", + "mimetypemagicdialog.h", + "mimetypemagicdialog.ui", + "mimetypesettings.cpp", + "mimetypesettings.h", "mimetypesettingspage.ui", - "minisplitter.cpp", "minisplitter.h", - "modemanager.cpp", "modemanager.h", - "navigationsubwidget.cpp", "navigationsubwidget.h", - "navigationwidget.cpp", "navigationwidget.h", - "opendocumentstreeview.cpp", "opendocumentstreeview.h", - "outputpane.cpp", "outputpane.h", - "outputpanemanager.cpp", "outputpanemanager.h", - "outputwindow.cpp", "outputwindow.h", - "patchtool.cpp", "patchtool.h", - "plugindialog.cpp", "plugindialog.h", - "reaper.cpp", "reaper.h", "reaper_p.h", - "rightpane.cpp", "rightpane.h", - "settingsdatabase.cpp", "settingsdatabase.h", - "shellcommand.cpp", "shellcommand.h", - "sidebar.cpp", "sidebar.h", - "sidebarwidget.cpp", "sidebarwidget.h", - "statusbarmanager.cpp", "statusbarmanager.h", - "statusbarwidget.cpp", "statusbarwidget.h", - "styleanimator.cpp", "styleanimator.h", - "systemsettings.cpp", "systemsettings.h", "systemsettings.ui", - "textdocument.cpp", "textdocument.h", - "themechooser.cpp", "themechooser.h", - "toolsettings.cpp", "toolsettings.h", - "variablechooser.cpp", "variablechooser.h", - "vcsmanager.cpp", "vcsmanager.h", - "versiondialog.cpp", "versiondialog.h", - "windowsupport.cpp", "windowsupport.h" + "minisplitter.cpp", + "minisplitter.h", + "modemanager.cpp", + "modemanager.h", + "navigationsubwidget.cpp", + "navigationsubwidget.h", + "navigationwidget.cpp", + "navigationwidget.h", + "opendocumentstreeview.cpp", + "opendocumentstreeview.h", + "outputpane.cpp", + "outputpane.h", + "outputpanemanager.cpp", + "outputpanemanager.h", + "outputwindow.cpp", + "outputwindow.h", + "patchtool.cpp", + "patchtool.h", + "plugindialog.cpp", + "plugindialog.h", + "reaper.cpp", + "reaper.h", + "reaper_p.h", + "rightpane.cpp", + "rightpane.h", + "settingsdatabase.cpp", + "settingsdatabase.h", + "shellcommand.cpp", + "shellcommand.h", + "sidebar.cpp", + "sidebar.h", + "sidebarwidget.cpp", + "sidebarwidget.h", + "statusbarmanager.cpp", + "statusbarmanager.h", + "statusbarwidget.cpp", + "statusbarwidget.h", + "styleanimator.cpp", + "styleanimator.h", + "systemsettings.cpp", + "systemsettings.h", + "systemsettings.ui", + "textdocument.cpp", + "textdocument.h", + "themechooser.cpp", + "themechooser.h", + "toolsettings.cpp", + "toolsettings.h", + "variablechooser.cpp", + "variablechooser.h", + "vcsmanager.cpp", + "vcsmanager.h", + "versiondialog.cpp", + "versiondialog.h", + "windowsupport.cpp", + "windowsupport.h", ] } diff --git a/src/plugins/coreplugin/menubarfilter.cpp b/src/plugins/coreplugin/menubarfilter.cpp new file mode 100644 index 00000000000..5c3c4414db8 --- /dev/null +++ b/src/plugins/coreplugin/menubarfilter.cpp @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "menubarfilter.h" + +#include "actionmanager/actioncontainer.h" +#include "actionmanager/actionmanager.h" +#include "coreconstants.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace Core::Internal; +using namespace Core; + +MenuBarFilter::MenuBarFilter() +{ + setId("Actions from the menu"); + setDisplayName(tr("Actions from the Menu")); + setShortcutString("t"); +} + +static const QList menuBarActions() +{ + QMenuBar *menuBar = Core::ActionManager::actionContainer(Constants::MENU_BAR)->menuBar(); + QTC_ASSERT(menuBar, return {}); + return menuBar->actions(); +} + +QList MenuBarFilter::matchesFor(QFutureInterface &future, + const QString &entry) +{ + Q_UNUSED(future); + static const QString separators = ". >/"; + static const QRegularExpression seperatorRegExp(QString("[%1]").arg(separators)); + QList entries; + QString normalized = entry; + normalized.replace(seperatorRegExp, separators.at(0)); + const QStringList entryPath = normalized.split(separators.at(0), QString::SkipEmptyParts); + QVector processedMenus; + for (QAction* action : menuBarActions()) + entries << matchesForAction(action, entryPath, QStringList(), processedMenus); + + return entries; +} + +void MenuBarFilter::accept(LocatorFilterEntry selection, QString *newText, + int *selectionStart, int *selectionLength) const +{ + Q_UNUSED(newText); + Q_UNUSED(selectionStart); + Q_UNUSED(selectionLength); + if (auto action = selection.internalData.value>()) + action->trigger(); +} + +void MenuBarFilter::refresh(QFutureInterface &future) +{ + Q_UNUSED(future); +} + +QList MenuBarFilter::matchesForAction(QAction *action, + const QStringList &entryPath, + const QStringList &path, + QVector &processedMenus) +{ + QList entries; + if (!action->isEnabled()) + return entries; + const QString text = Utils::stripAccelerator(action->text()); + if (QMenu *menu = action->menu()) { + if (processedMenus.contains(menu)) + return entries; + processedMenus.append(menu); + if (menu->isEnabled()) { + const QList &actions = menu->actions(); + QStringList menuPath(path); + menuPath << text; + for (QAction *menuAction : actions) + entries << matchesForAction(menuAction, entryPath, menuPath, processedMenus); + } + } else if (!text.isEmpty()) { + int entryIndex = 0; + int entryLength = 0; + int pathIndex = 0; + LocatorFilterEntry::HighlightInfo::DataType highlightType = + LocatorFilterEntry::HighlightInfo::DisplayName; + const QString pathText = path.join(" > "); + QStringList actionPath(path); + if (!entryPath.isEmpty()) { + actionPath << text; + for (const QString &entry : entryPath) { + const QRegularExpression re(".*" + entry + ".*", + QRegularExpression::CaseInsensitiveOption); + pathIndex = actionPath.indexOf(re, pathIndex); + if (pathIndex < 0) + return entries; + } + const QString &lastEntry(entryPath.last()); + entryLength = lastEntry.length(); + entryIndex = text.indexOf(lastEntry, 0, Qt::CaseInsensitive); + if (entryIndex >= 0) { + highlightType = LocatorFilterEntry::HighlightInfo::DisplayName; + } else { + entryIndex = pathText.indexOf(lastEntry, 0, Qt::CaseInsensitive); + QTC_ASSERT(entryIndex >= 0, return entries); + highlightType = LocatorFilterEntry::HighlightInfo::ExtraInfo; + } + } + LocatorFilterEntry filterEntry(this, text, QVariant(), action->icon()); + filterEntry.internalData.setValue(QPointer(action)); + filterEntry.extraInfo = pathText; + filterEntry.highlightInfo = {entryIndex, entryLength, highlightType}; + entries << filterEntry; + } + return entries; +} + +static void requestMenuUpdate(const QAction* action) +{ + if (QMenu *menu = action->menu()) { + emit menu->aboutToShow(); + const QList &actions = menu->actions(); + for (const QAction *menuActions : actions) + requestMenuUpdate(menuActions); + } +} + +void Core::Internal::MenuBarFilter::prepareSearch(const QString &entry) +{ + Q_UNUSED(entry); + for (const QAction *action : menuBarActions()) + requestMenuUpdate(action); +} diff --git a/src/plugins/coreplugin/menubarfilter.h b/src/plugins/coreplugin/menubarfilter.h new file mode 100644 index 00000000000..9251df7da26 --- /dev/null +++ b/src/plugins/coreplugin/menubarfilter.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 + +QT_BEGIN_NAMESPACE +class QAction; +class QMenu; +QT_END_NAMESPACE + +namespace Core { +namespace Internal { + +class MenuBarFilter : public ILocatorFilter +{ +public: + MenuBarFilter(); + + QList matchesFor(QFutureInterface &future, + const QString &entry) override; + void accept(LocatorFilterEntry selection, QString *newText, + int *selectionStart, int *selectionLength) const override; + void refresh(QFutureInterface &future) override; + void prepareSearch(const QString &entry) override; +private: + QList matchesForAction(QAction *action, + const QStringList &entryPath, + const QStringList &path, + QVector &processedMenus); + +}; + +} // namespace Internal +} // namespace Core From f1d57a835fb6463a771e7854cd40eca768dd53c7 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Wed, 10 Jan 2018 15:08:21 +0100 Subject: [PATCH 02/16] QtSupport: remove latin1 calls Change-Id: I34fa89f3755740396bd8892bce96e515b5afefa5 Reviewed-by: Tobias Hunger --- src/plugins/qtsupport/baseqtversion.cpp | 161 ++++++++++++------------ 1 file changed, 80 insertions(+), 81 deletions(-) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 3b022db2332..7f6b15df05a 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -381,15 +381,15 @@ QString BaseQtVersion::defaultUnexpandedDisplayName(const FileName &qmakePath, b QDir dir = qmakePath.toFileInfo().absoluteDir(); do { const QString dirName = dir.dirName(); - if (dirName == QLatin1String("usr")) { // System-installed Qt. + if (dirName == "usr") { // System-installed Qt. location = QCoreApplication::translate("QtVersion", "System"); break; } location = dirName; // Also skip default checkouts named 'qt'. Parent dir might have descriptive name. - if (dirName.compare(QLatin1String("bin"), Qt::CaseInsensitive) - && dirName.compare(QLatin1String("qtbase"), Qt::CaseInsensitive) - && dirName.compare(QLatin1String("qt"), Qt::CaseInsensitive)) { + if (dirName.compare("bin", Qt::CaseInsensitive) + && dirName.compare("qtbase", Qt::CaseInsensitive) + && dirName.compare("qt", Qt::CaseInsensitive)) { break; } } while (!dir.isRoot() && dir.cdUp()); @@ -526,7 +526,7 @@ QList BaseQtVersion::validateKit(const Kit *k) QString qtAbiString; foreach (const Abi &qtAbi, qtAbis) { if (!qtAbiString.isEmpty()) - qtAbiString.append(QLatin1Char(' ')); + qtAbiString.append(' '); qtAbiString.append(qtAbi.toString()); if (!fullMatch) @@ -588,13 +588,13 @@ FileName BaseQtVersion::mkspecsPath() const if (result.isEmpty()) result = FileName::fromUserInput(qmakeProperty("QMAKE_MKSPECS")); else - result.appendPath(QLatin1String("mkspecs")); + result.appendPath("mkspecs"); return result; } FileName BaseQtVersion::qmlBinPath() const { - return FileName::fromUserInput(m_mkspecValues.value(QLatin1String("QT.qml.bins"))); + return FileName::fromUserInput(m_mkspecValues.value("QT.qml.bins")); } FileName BaseQtVersion::librarySearchPath() const @@ -622,13 +622,13 @@ FileNameList BaseQtVersion::directoriesToIgnoreInProjectTree() const QString BaseQtVersion::qtNamespace() const { ensureMkSpecParsed(); - return m_mkspecValues.value(QLatin1String(MKSPEC_VALUE_NAMESPACE)); + return m_mkspecValues.value(MKSPEC_VALUE_NAMESPACE); } QString BaseQtVersion::qtLibInfix() const { ensureMkSpecParsed(); - return m_mkspecValues.value(QLatin1String(MKSPEC_VALUE_LIBINFIX)); + return m_mkspecValues.value(MKSPEC_VALUE_LIBINFIX); } bool BaseQtVersion::isFrameworkBuild() const @@ -654,15 +654,15 @@ void BaseQtVersion::setId(int id) void BaseQtVersion::fromMap(const QVariantMap &map) { - m_id = map.value(QLatin1String(Constants::QTVERSIONID)).toInt(); + m_id = map.value(Constants::QTVERSIONID).toInt(); if (m_id == -1) // this happens on adding from installer, see updateFromInstaller => get a new unique id m_id = QtVersionManager::getUniqueId(); - m_unexpandedDisplayName = map.value(QLatin1String(Constants::QTVERSIONNAME)).toString(); - m_isAutodetected = map.value(QLatin1String(QTVERSIONAUTODETECTED)).toBool(); + m_unexpandedDisplayName = map.value(Constants::QTVERSIONNAME).toString(); + m_isAutodetected = map.value(QTVERSIONAUTODETECTED).toBool(); if (m_isAutodetected) - m_autodetectionSource = map.value(QLatin1String(QTVERSIONAUTODETECTIONSOURCE)).toString(); - QString string = map.value(QLatin1String(QTVERSIONQMAKEPATH)).toString(); - if (string.startsWith(QLatin1Char('~'))) + m_autodetectionSource = map.value(QTVERSIONAUTODETECTIONSOURCE).toString(); + QString string = map.value(QTVERSIONQMAKEPATH).toString(); + if (string.startsWith('~')) string.remove(0, 1).prepend(QDir::homePath()); QFileInfo fi(string); @@ -679,12 +679,12 @@ void BaseQtVersion::fromMap(const QVariantMap &map) QVariantMap BaseQtVersion::toMap() const { QVariantMap result; - result.insert(QLatin1String(Constants::QTVERSIONID), uniqueId()); - result.insert(QLatin1String(Constants::QTVERSIONNAME), unexpandedDisplayName()); - result.insert(QLatin1String(QTVERSIONAUTODETECTED), isAutodetected()); + result.insert(Constants::QTVERSIONID, uniqueId()); + result.insert(Constants::QTVERSIONNAME, unexpandedDisplayName()); + result.insert(QTVERSIONAUTODETECTED, isAutodetected()); if (isAutodetected()) - result.insert(QLatin1String(QTVERSIONAUTODETECTIONSOURCE), autodetectionSource()); - result.insert(QLatin1String(QTVERSIONQMAKEPATH), qmakeCommand().toString()); + result.insert(QTVERSIONAUTODETECTIONSOURCE, autodetectionSource()); + result.insert(QTVERSIONQMAKEPATH, qmakeCommand().toString()); return result; } @@ -854,16 +854,16 @@ QString BaseQtVersion::toHtml(bool verbose) const foreach (const ProKey &key, keys) { const QString &value = vInfo.value(key).toQString(); QString variableName = key.toQString(); - if (variableName != QLatin1String("QMAKE_MKSPECS") - && !variableName.endsWith(QLatin1String("/raw"))) { + if (variableName != "QMAKE_MKSPECS" + && !variableName.endsWith("/raw")) { bool isPath = false; - if (variableName.contains(QLatin1String("_HOST_")) - || variableName.contains(QLatin1String("_INSTALL_"))) { - if (!variableName.endsWith(QLatin1String("/get"))) + if (variableName.contains("_HOST_") + || variableName.contains("_INSTALL_")) { + if (!variableName.endsWith("/get")) continue; variableName.chop(4); isPath = true; - } else if (variableName == QLatin1String("QT_SYSROOT")) { + } else if (variableName == "QT_SYSROOT") { isPath = true; } str << "
" << variableName <<  "
"; @@ -937,7 +937,7 @@ QString BaseQtVersion::findHostBinary(HostBinaries binary) const switch (binary) { case Designer: case Linguist: - baseDir = m_mkspecValues.value(QLatin1String("QT.designer.bins")); + baseDir = m_mkspecValues.value("QT.designer.bins"); break; case Uic: case QScxmlc: @@ -951,33 +951,32 @@ QString BaseQtVersion::findHostBinary(HostBinaries binary) const if (baseDir.isEmpty()) return QString(); - if (!baseDir.endsWith(QLatin1Char('/'))) - baseDir += QLatin1Char('/'); + if (!baseDir.endsWith('/')) + baseDir += '/'; QStringList possibleCommands; switch (binary) { case Designer: if (HostOsInfo::isMacHost()) - possibleCommands << QLatin1String("Designer.app/Contents/MacOS/Designer"); + possibleCommands << "Designer.app/Contents/MacOS/Designer"; else - possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("designer")); + possibleCommands << HostOsInfo::withExecutableSuffix("designer"); break; case Linguist: if (HostOsInfo::isMacHost()) - possibleCommands << QLatin1String("Linguist.app/Contents/MacOS/Linguist"); + possibleCommands << "Linguist.app/Contents/MacOS/Linguist"; else - possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("linguist")); + possibleCommands << HostOsInfo::withExecutableSuffix("linguist"); break; case Uic: if (HostOsInfo::isWindowsHost()) { - possibleCommands << QLatin1String("uic.exe"); + possibleCommands << "uic.exe"; } else { - possibleCommands << QLatin1String("uic-qt4") << QLatin1String("uic4") - << QLatin1String("uic"); + possibleCommands << "uic-qt4" << "uic4" << "uic"; } break; case QScxmlc: - possibleCommands << HostOsInfo::withExecutableSuffix(QLatin1String("qscxmlc")); + possibleCommands << HostOsInfo::withExecutableSuffix("qscxmlc"); break; default: Q_ASSERT(false); @@ -1018,7 +1017,7 @@ void BaseQtVersion::updateMkspec() const m_mkspec = m_mkspec.relativeChildPath(baseMkspecDir); // qDebug() << "Setting mkspec to"<values(QLatin1String("CONFIG")); - m_qtConfigValues = evaluator->values(QLatin1String("QT_CONFIG")); + m_configValues = evaluator->values("CONFIG"); + m_qtConfigValues = evaluator->values("QT_CONFIG"); m_defaultConfigIsDebugAndRelease = false; m_frameworkBuild = false; foreach (const QString &value, m_configValues) { - if (value == QLatin1String("debug")) + if (value == "debug") m_defaultConfigIsDebug = true; - else if (value == QLatin1String("release")) + else if (value == "release") m_defaultConfigIsDebug = false; - else if (value == QLatin1String("build_all")) + else if (value == "build_all") m_defaultConfigIsDebugAndRelease = true; - else if (value == QLatin1String("qt_framework")) + else if (value == "qt_framework") m_frameworkBuild = true; } - const QString designerBins = QLatin1String("QT.designer.bins"); - const QString qmlBins = QLatin1String("QT.qml.bins"); - const QString declarativeBins = QLatin1String("QT.declarative.bins"); - const QString libinfix = QLatin1String(MKSPEC_VALUE_LIBINFIX); - const QString ns = QLatin1String(MKSPEC_VALUE_NAMESPACE); + const QString designerBins = "QT.designer.bins"; + const QString qmlBins = "QT.qml.bins"; + const QString declarativeBins = "QT.declarative.bins"; + const QString libinfix = MKSPEC_VALUE_LIBINFIX; + const QString ns = MKSPEC_VALUE_NAMESPACE; m_mkspecValues.insert(designerBins, evaluator->value(designerBins)); m_mkspecValues.insert(qmlBins, evaluator->value(qmlBins)); m_mkspecValues.insert(declarativeBins, evaluator->value(declarativeBins)); @@ -1114,11 +1113,11 @@ bool BaseQtVersion::hasMkspec(const FileName &spec) const return true; // default spec of a Qt version QDir mkspecDir = QDir(QDir::fromNativeSeparators(qmakeProperty("QT_HOST_DATA")) - + QLatin1String("/mkspecs/")); + + "/mkspecs/"); const QString absSpec = mkspecDir.absoluteFilePath(spec.toString()); if (QFileInfo(absSpec).isDir() && QFileInfo(absSpec + "/qmake.conf").isFile()) return true; - mkspecDir.setPath(sourcePath().toString() + QLatin1String("/mkspecs/")); + mkspecDir.setPath(sourcePath().toString() + "/mkspecs/"); const QString absSrcSpec = mkspecDir.absoluteFilePath(spec.toString()); return absSrcSpec != absSpec && QFileInfo(absSrcSpec).isDir() @@ -1230,7 +1229,7 @@ QString BaseQtVersion::qmakeProperty(const QHash &versionInfo, variant == PropertyVariantGet ? "/get" : "/src")))).toQString(); if (!val.isNull()) return val; - return versionInfo.value(ProKey(QString::fromLatin1(name))).toQString(); + return versionInfo.value(ProKey(name)).toQString(); } QString BaseQtVersion::qmakeProperty(const QByteArray &name, PropertyVariant variant) const @@ -1354,7 +1353,7 @@ void BaseQtVersion::populateQmlFileFinder(FileInProjectFinder *finder, const Tar void BaseQtVersion::addToEnvironment(const Kit *k, Environment &env) const { Q_UNUSED(k); - env.set(QLatin1String("QTDIR"), QDir::toNativeSeparators(qmakeProperty("QT_HOST_DATA"))); + env.set("QTDIR", QDir::toNativeSeparators(qmakeProperty("QT_HOST_DATA"))); } // Some Qt versions may require environment settings for qmake to work @@ -1445,7 +1444,7 @@ static QByteArray runQmakeQuery(const FileName &binary, const Environment &env, QProcess process; process.setEnvironment(env.toStringList()); - process.start(binary.toString(), QStringList(QLatin1String("-query")), QIODevice::ReadOnly); + process.start(binary.toString(), QStringList("-query"), QIODevice::ReadOnly); if (!process.waitForStarted()) { *error = QCoreApplication::translate("QtVersion", "Cannot start \"%1\": %2").arg(binary.toUserOutput()).arg(process.errorString()); @@ -1512,7 +1511,7 @@ FileName BaseQtVersion::mkspecDirectoryFromVersionInfo(const QHash &versionInfo) @@ -1524,7 +1523,7 @@ FileName BaseQtVersion::mkspecFromVersionInfo(const QHash &ve bool qt5 = false; QString theSpec = qmakeProperty(versionInfo, "QMAKE_XSPEC"); if (theSpec.isEmpty()) - theSpec = QLatin1String("default"); + theSpec = "default"; else qt5 = true; @@ -1535,7 +1534,7 @@ FileName BaseQtVersion::mkspecFromVersionInfo(const QHash &ve if (HostOsInfo::isWindowsHost()) { if (!qt5) { - QFile f2(mkspecFullPath.toString() + QLatin1String("/qmake.conf")); + QFile f2(mkspecFullPath.toString() + "/qmake.conf"); if (f2.exists() && f2.open(QIODevice::ReadOnly)) { while (!f2.atEnd()) { QByteArray line = f2.readLine(); @@ -1543,16 +1542,16 @@ FileName BaseQtVersion::mkspecFromVersionInfo(const QHash &ve const QList &temp = line.split('='); if (temp.size() == 2) { QString possibleFullPath = QString::fromLocal8Bit(temp.at(1).trimmed().constData()); - if (possibleFullPath.contains(QLatin1Char('$'))) { // QTBUG-28792 - const QRegularExpression rex(QLatin1String("\\binclude\\(([^)]+)/qmake\\.conf\\)")); + if (possibleFullPath.contains('$')) { // QTBUG-28792 + const QRegularExpression rex("\\binclude\\(([^)]+)/qmake\\.conf\\)"); const QRegularExpressionMatch match = rex.match(QString::fromLocal8Bit(f2.readAll())); if (match.hasMatch()) { - possibleFullPath = mkspecFullPath.toString() + QLatin1Char('/') + possibleFullPath = mkspecFullPath.toString() + '/' + match.captured(1); } } // We sometimes get a mix of different slash styles here... - possibleFullPath = possibleFullPath.replace(QLatin1Char('\\'), QLatin1Char('/')); + possibleFullPath = possibleFullPath.replace('\\', '/'); if (QFileInfo::exists(possibleFullPath)) // Only if the path exists mkspecFullPath = FileName::fromUserInput(possibleFullPath); } @@ -1564,7 +1563,7 @@ FileName BaseQtVersion::mkspecFromVersionInfo(const QHash &ve } } else { if (HostOsInfo::isMacHost()) { - QFile f2(mkspecFullPath.toString() + QLatin1String("/qmake.conf")); + QFile f2(mkspecFullPath.toString() + "/qmake.conf"); if (f2.exists() && f2.open(QIODevice::ReadOnly)) { while (!f2.atEnd()) { QByteArray line = f2.readLine(); @@ -1575,7 +1574,7 @@ FileName BaseQtVersion::mkspecFromVersionInfo(const QHash &ve if (value.contains("XCODE")) { // we don't want to generate xcode projects... // qDebug() << "default mkspec is xcode, falling back to g++"; - return baseMkspecDir.appendPath(QLatin1String("macx-g++")); + return baseMkspecDir.appendPath("macx-g++"); } } break; @@ -1603,14 +1602,14 @@ FileName BaseQtVersion::sourcePath(const QHash &versionInfo) const QString installData = qmakeProperty(versionInfo, "QT_INSTALL_PREFIX"); QString sourcePath = installData; - QFile qmakeCache(installData + QLatin1String("/.qmake.cache")); + QFile qmakeCache(installData + "/.qmake.cache"); if (qmakeCache.exists() && qmakeCache.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream stream(&qmakeCache); while (!stream.atEnd()) { QString line = stream.readLine().trimmed(); - if (line.startsWith(QLatin1String("QT_SOURCE_TREE"))) { - sourcePath = line.split(QLatin1Char('=')).at(1).trimmed(); - if (sourcePath.startsWith(QLatin1String("$$quote("))) { + if (line.startsWith("QT_SOURCE_TREE")) { + sourcePath = line.split('=').at(1).trimmed(); + if (sourcePath.startsWith("$$quote(")) { sourcePath.remove(0, 8); sourcePath.chop(1); } @@ -1627,7 +1626,7 @@ bool BaseQtVersion::isInSourceDirectory(const Utils::FileName &filePath) if (source.isEmpty()) return false; QDir dir = QDir(source.toString()); - if (dir.dirName() == QLatin1String("qtbase")) + if (dir.dirName() == "qtbase") dir.cdUp(); return filePath.isChildOf(dir); } @@ -1637,7 +1636,7 @@ bool BaseQtVersion::isSubProject(const Utils::FileName &filePath) const const Utils::FileName &source = sourcePath(); if (!source.isEmpty()) { QDir dir = QDir(source.toString()); - if (dir.dirName() == QLatin1String("qtbase")) + if (dir.dirName() == "qtbase") dir.cdUp(); if (filePath.isChildOf(dir)) @@ -1711,7 +1710,7 @@ bool BaseQtVersion::isQtQuickCompilerSupported(QString *reason) const } const QString qtQuickCompilerExecutable = - HostOsInfo::withExecutableSuffix(binPath().toString() + QLatin1String("/qtquickcompiler")); + HostOsInfo::withExecutableSuffix(binPath().toString() + "/qtquickcompiler"); if (!QFileInfo::exists(qtQuickCompilerExecutable)) { if (reason) *reason = QCoreApplication::translate("BaseQtVersion", "This Qt Version does not contain Qt Quick Compiler."); @@ -1739,22 +1738,22 @@ FileNameList BaseQtVersion::qtCorePaths() const foreach (const QFileInfo &info, infoList) { const QString file = info.fileName(); if (info.isDir() - && file.startsWith(QLatin1String("QtCore")) - && file.endsWith(QLatin1String(".framework"))) { + && file.startsWith("QtCore") + && file.endsWith(".framework")) { // handle Framework FileName lib(info); - dynamicLibs.append(lib.appendPath(file.left(file.lastIndexOf(QLatin1Char('.'))))); + dynamicLibs.append(lib.appendPath(file.left(file.lastIndexOf('.')))); } else if (info.isReadable()) { - if (file.startsWith(QLatin1String("libQtCore")) - || file.startsWith(QLatin1String("libQt5Core")) - || file.startsWith(QLatin1String("QtCore")) - || file.startsWith(QLatin1String("Qt5Core"))) { - if (file.endsWith(QLatin1String(".a")) || file.endsWith(QLatin1String(".lib"))) + if (file.startsWith("libQtCore") + || file.startsWith("libQt5Core") + || file.startsWith("QtCore") + || file.startsWith("Qt5Core")) { + if (file.endsWith(".a") || file.endsWith(".lib")) staticLibs.append(FileName(info)); - else if (file.endsWith(QLatin1String(".dll")) + else if (file.endsWith(".dll") || file.endsWith(QString::fromLatin1(".so.") + versionString) - || file.endsWith(QLatin1String(".so")) - || file.endsWith(QLatin1Char('.') + versionString + QLatin1String(".dylib"))) + || file.endsWith(".so") + || file.endsWith(QLatin1Char('.') + versionString + ".dylib")) dynamicLibs.append(FileName(info)); } } From d226c84cca3d20cd6ed7ca0a8b9a899c91bd728b Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 15 Jan 2018 10:38:27 +0100 Subject: [PATCH 03/16] AutoTest: Omit tests that cannot get handled We might find some test constructs that cannot get run without further knowledge which should be provided by the user (e.g. plugin unit tests of QC) Omit these tests to avoid user irritation and useless warnings. Change-Id: Ia8f533b931a7c58bd768697c0915cbdd44225534 Reviewed-by: David Schulz --- src/plugins/autotest/qtest/qttestparser.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/plugins/autotest/qtest/qttestparser.cpp b/src/plugins/autotest/qtest/qttestparser.cpp index 482e14f60b2..6facee38a9e 100644 --- a/src/plugins/autotest/qtest/qttestparser.cpp +++ b/src/plugins/autotest/qtest/qttestparser.cpp @@ -271,6 +271,13 @@ static QtTestCodeLocationList tagLocationsFor(const QtTestParseResult *func, return QtTestCodeLocationList(); } +static bool isQObject(const CPlusPlus::Document::Ptr &declaringDoc) +{ + const QString file = declaringDoc->fileName(); + return (Utils::HostOsInfo::isMacHost() && file.endsWith("QtCore.framework/Headers/qobject.h")) + || file.endsWith("QtCore/qobject.h") || file.endsWith("kernel/qobject.h"); +} + static bool handleQtTest(QFutureInterface futureInterface, CPlusPlus::Document::Ptr document, const CPlusPlus::Snapshot &snapshot, @@ -303,6 +310,10 @@ static bool handleQtTest(QFutureInterface futureInterface, fetchAndMergeBaseTestFunctions( visitor.baseClasses(), testFunctions, declaringDoc, snapshot); + // handle tests that are not runnable without more information (plugin unit test of QC) + if (testFunctions.isEmpty() && testCaseName == "QObject" && isQObject(declaringDoc)) + return true; // we did not handle it, but we do not expect any test defined there either + const QSet &files = filesWithDataFunctionDefinitions(testFunctions); // TODO: change to QHash<> From 67f14eb32dd11f46f4bcbc114859a96d60f664d9 Mon Sep 17 00:00:00 2001 From: Jochen Becher Date: Fri, 12 Jan 2018 23:12:29 +0100 Subject: [PATCH 04/16] ModelEditor: Improve component model creation Ignore include files that only includes one file with the same name. Change-Id: I1cac46511b44fec2aa1b3f9b4a6ae644d4ed5e9a Reviewed-by: Tobias Hunger --- .../modeleditor/componentviewcontroller.cpp | 47 +++++++++++++++---- .../modeleditor/componentviewcontroller.h | 5 +- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/plugins/modeleditor/componentviewcontroller.cpp b/src/plugins/modeleditor/componentviewcontroller.cpp index 1c35e912021..c790fe64dd4 100644 --- a/src/plugins/modeleditor/componentviewcontroller.cpp +++ b/src/plugins/modeleditor/componentviewcontroller.cpp @@ -161,6 +161,16 @@ void UpdateIncludeDependenciesVisitor::visitMComponent(qmt::MComponent *componen if (document) { foreach (const CPlusPlus::Document::Include &include, document->resolvedIncludes()) { QString includeFilePath = include.resolvedFileName(); + // replace proxy header with real one + CPlusPlus::Document::Ptr includeDocument = snapshot.document(includeFilePath); + if (includeDocument) { + QList includes = includeDocument->resolvedIncludes(); + if (includes.count() == 1 && + QFileInfo(includes.at(0).resolvedFileName()).fileName() == QFileInfo(includeFilePath).fileName()) + { + includeFilePath = includes.at(0).resolvedFileName(); + } + } qmt::MComponent *includeComponent = findComponentFromFilePath(includeFilePath); if (includeComponent && includeComponent != component) { // add dependency between components @@ -390,7 +400,8 @@ void ComponentViewController::createComponentModel(const QString &filePath, const QString &anchorFolder) { d->diagramSceneController->modelController()->startResetModel(); - doCreateComponentModel(filePath, diagram, anchorFolder); + doCreateComponentModel(filePath, diagram, anchorFolder, false); + doCreateComponentModel(filePath, diagram, anchorFolder, true); d->diagramSceneController->modelController()->finishResetModel(true); } @@ -404,7 +415,8 @@ void ComponentViewController::updateIncludeDependencies(qmt::MPackage *rootPacka d->diagramSceneController->modelController()->finishResetModel(true); } -void ComponentViewController::doCreateComponentModel(const QString &filePath, qmt::MDiagram *diagram, const QString &anchorFolder) +void ComponentViewController::doCreateComponentModel(const QString &filePath, qmt::MDiagram *diagram, + const QString &anchorFolder, bool scanHeaders) { for (const QString &fileName : QDir(filePath).entryList(QDir::Files)) { QString file = filePath + "/" + fileName; @@ -413,18 +425,20 @@ void ComponentViewController::doCreateComponentModel(const QString &filePath, qm bool isSource = false; CppTools::ProjectFile::Kind kind = CppTools::ProjectFile::classify(file); switch (kind) { - case CppTools::ProjectFile::AmbiguousHeader: - case CppTools::ProjectFile::CHeader: case CppTools::ProjectFile::CSource: - case CppTools::ProjectFile::CXXHeader: case CppTools::ProjectFile::CXXSource: case CppTools::ProjectFile::ObjCSource: - case CppTools::ProjectFile::ObjCHeader: case CppTools::ProjectFile::ObjCXXSource: - case CppTools::ProjectFile::ObjCXXHeader: case CppTools::ProjectFile::CudaSource: case CppTools::ProjectFile::OpenCLSource: - isSource = true; + isSource = !scanHeaders; + break; + case CppTools::ProjectFile::AmbiguousHeader: + case CppTools::ProjectFile::CHeader: + case CppTools::ProjectFile::CXXHeader: + case CppTools::ProjectFile::ObjCHeader: + case CppTools::ProjectFile::ObjCXXHeader: + isSource = scanHeaders && !isProxyHeader(file); break; case CppTools::ProjectFile::Unclassified: case CppTools::ProjectFile::Unsupported: @@ -450,9 +464,24 @@ void ComponentViewController::doCreateComponentModel(const QString &filePath, qm } for (const QString &fileName : QDir(filePath).entryList(QDir::Dirs|QDir::NoDotAndDotDot)) { QString file = filePath + "/" + fileName; - doCreateComponentModel(file, diagram, anchorFolder); + doCreateComponentModel(file, diagram, anchorFolder, scanHeaders); } } +bool ComponentViewController::isProxyHeader(const QString &file) const +{ + CppTools::CppModelManager *cppModelManager = CppTools::CppModelManager::instance(); + CPlusPlus::Snapshot snapshot = cppModelManager->snapshot(); + + CPlusPlus::Document::Ptr document = snapshot.document(file); + if (document) { + QList includes = document->resolvedIncludes(); + if (includes.count() != 1) + return false; + return QFileInfo(includes.at(0).resolvedFileName()).fileName() == QFileInfo(file).fileName(); + } + return false; +} + } // namespace Internal } // namespace ModelEditor diff --git a/src/plugins/modeleditor/componentviewcontroller.h b/src/plugins/modeleditor/componentviewcontroller.h index 98f4ac0ca6f..584bc55b50d 100644 --- a/src/plugins/modeleditor/componentviewcontroller.h +++ b/src/plugins/modeleditor/componentviewcontroller.h @@ -58,8 +58,9 @@ public: void updateIncludeDependencies(qmt::MPackage *rootPackage); private: - void doCreateComponentModel(const QString &filePath, - qmt::MDiagram *diagram, const QString &anchorFolder); + void doCreateComponentModel(const QString &filePath, qmt::MDiagram *diagram, + const QString &anchorFolder, bool scanHeaders); + bool isProxyHeader(const QString &file) const; ComponentViewControllerPrivate *d; }; From 753bf8a73607fb5b5ee27584b6277ce359b27b8b Mon Sep 17 00:00:00 2001 From: Jochen Becher Date: Sat, 13 Jan 2018 12:45:26 +0100 Subject: [PATCH 05/16] ModelEditor: Improve performance of component model creation Change-Id: I93ca27fc14692979314be90c0230d2672de66f04 Reviewed-by: Tobias Hunger --- src/plugins/modeleditor/componentviewcontroller.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/modeleditor/componentviewcontroller.cpp b/src/plugins/modeleditor/componentviewcontroller.cpp index c790fe64dd4..52501649cd8 100644 --- a/src/plugins/modeleditor/componentviewcontroller.cpp +++ b/src/plugins/modeleditor/componentviewcontroller.cpp @@ -133,6 +133,7 @@ private: private: qmt::ModelController *m_modelController = nullptr; QMultiHash m_filePaths; + QHash m_filePathComponentsMap; }; void UpdateIncludeDependenciesVisitor::setModelController(qmt::ModelController *modelController) @@ -322,10 +323,16 @@ void UpdateIncludeDependenciesVisitor::collectElementPaths(const ProjectExplorer qmt::MComponent *UpdateIncludeDependenciesVisitor::findComponentFromFilePath(const QString &filePath) { + const auto it = m_filePathComponentsMap.find(filePath); + if (it != m_filePathComponentsMap.cend()) + return it.value(); + FindComponentFromFilePath visitor; visitor.setFilePath(filePath); m_modelController->rootPackage()->accept(&visitor); - return visitor.component(); + qmt::MComponent *component = visitor.component(); + m_filePathComponentsMap.insert(filePath, component); + return component; } bool UpdateIncludeDependenciesVisitor::haveDependency(const qmt::MObject *source, From 9660c595506cb842333b2d595888a8257ceb0094 Mon Sep 17 00:00:00 2001 From: Jochen Becher Date: Sat, 13 Jan 2018 12:49:02 +0100 Subject: [PATCH 06/16] ModelEditor: Improve performance of loading large models Change-Id: Ic162d4805827cae9d34d7af9b6d56f3580b0f41d Reviewed-by: Tobias Hunger --- .../qmt/stereotype/stereotypecontroller.cpp | 50 +++++++++++++++++-- src/libs/modelinglib/qmt/style/style.h | 3 ++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp index 0db6b692467..5f70cb77da0 100644 --- a/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp +++ b/src/libs/modelinglib/qmt/stereotype/stereotypecontroller.cpp @@ -43,6 +43,47 @@ namespace qmt { +namespace { + +struct IconKey { + IconKey(StereotypeIcon::Element element, const QList &stereotypes, const QString &defaultIconPath, + const Uid &styleUid, const QSize &size, const QMarginsF &margins, qreal lineWidth) + : m_element(element), + m_stereotypes(stereotypes), + m_defaultIconPath(defaultIconPath), + m_styleUid(styleUid), + m_size(size), + m_margins(margins), + m_lineWidth(lineWidth) + { + } + + const StereotypeIcon::Element m_element; + const QList m_stereotypes; + const QString m_defaultIconPath; + const Uid m_styleUid; + const QSize m_size; + const QMarginsF m_margins; + const qreal m_lineWidth; +}; + +bool operator==(const IconKey &lhs, const IconKey &rhs) { + return lhs.m_element == rhs.m_element + && lhs.m_stereotypes == rhs.m_stereotypes + && lhs.m_defaultIconPath == rhs.m_defaultIconPath + && lhs.m_styleUid == rhs.m_styleUid + && lhs.m_size == rhs.m_size + && lhs.m_margins == rhs.m_margins + && lhs.m_lineWidth == rhs.m_lineWidth; +} + +uint qHash(const IconKey &key) { + return ::qHash(key.m_element) + qHash(key.m_stereotypes) + qHash(key.m_defaultIconPath) + + qHash(key.m_styleUid) + ::qHash(key.m_size.width()) + ::qHash(key.m_size.height()); +} + +} + class StereotypeController::StereotypeControllerPrivate { public: @@ -51,6 +92,7 @@ public: QHash m_relationIdToCustomRelationMap; QList m_toolbars; QList m_elementToolbars; + QHash m_iconMap; }; StereotypeController::StereotypeController(QObject *parent) : @@ -131,9 +173,10 @@ QIcon StereotypeController::createIcon(StereotypeIcon::Element element, const QL const QString &defaultIconPath, const Style *style, const QSize &size, const QMarginsF &margins, qreal lineWidth) { - // TODO implement cache with key build from element, stereotypes, defaultIconPath, style, size and margins - // TODO implement unique id for style which can be used as key - QIcon icon; + IconKey key(element, stereotypes, defaultIconPath, style->uid(), size, margins, lineWidth); + QIcon icon = d->m_iconMap.value(key); + if (!icon.isNull()) + return icon; QString stereotypeIconId = findStereotypeIconId(element, stereotypes); if (!stereotypeIconId.isEmpty()) { StereotypeIcon stereotypeIcon = findStereotypeIcon(stereotypeIconId); @@ -202,6 +245,7 @@ QIcon StereotypeController::createIcon(StereotypeIcon::Element element, const QL } if (icon.isNull() && !defaultIconPath.isEmpty()) icon = QIcon(defaultIconPath); + d->m_iconMap.insert(key, icon); return icon; } diff --git a/src/libs/modelinglib/qmt/style/style.h b/src/libs/modelinglib/qmt/style/style.h index 9add43d26e8..b2012e4f042 100644 --- a/src/libs/modelinglib/qmt/style/style.h +++ b/src/libs/modelinglib/qmt/style/style.h @@ -26,6 +26,7 @@ #pragma once #include "qmt/infrastructure/qmt_global.h" +#include "qmt/infrastructure/uid.h" #include #include @@ -45,6 +46,7 @@ public: explicit Style(Type type); virtual ~Style(); + Uid uid() const { return m_uid; } Type type() const { return m_type; } QPen linePen() const { return m_linePen; } void setLinePen(const QPen &pen); @@ -68,6 +70,7 @@ public: void setHeaderFont(const QFont &font); private: + Uid m_uid; Type m_type; QPen m_linePen; QPen m_outerLinePen; From 53a744a6dfe3999b86e9adaab3c05d60322a251e Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 11 Jan 2018 16:46:45 +0100 Subject: [PATCH 07/16] CppTools: Improve a function name Change-Id: I30f9048aff18440d8cc6a6247f5fd5bcdba5058d Reviewed-by: Ivan Donchevskii --- src/plugins/clangcodemodel/clangmodelmanagersupport.cpp | 2 +- src/plugins/clangcodemodel/clangmodelmanagersupport.h | 2 +- src/plugins/cppeditor/cppeditordocument.cpp | 2 +- src/plugins/cpptools/cppmodelmanager.cpp | 4 ++-- src/plugins/cpptools/cppmodelmanager.h | 2 +- src/plugins/cpptools/cppmodelmanagersupport.h | 2 +- src/plugins/cpptools/cppmodelmanagersupportinternal.cpp | 2 +- src/plugins/cpptools/cppmodelmanagersupportinternal.h | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index f73c5fe4e4a..f66392d64ef 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -121,7 +121,7 @@ CppTools::RefactoringEngineInterface &ModelManagerSupportClang::refactoringEngin return *m_refactoringEngine; } -CppTools::BaseEditorDocumentProcessor *ModelManagerSupportClang::editorDocumentProcessor( +CppTools::BaseEditorDocumentProcessor *ModelManagerSupportClang::createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) { return new ClangEditorDocumentProcessor(m_communicator, baseTextDocument); diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index e87a7f162e8..842c1d75fa2 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -61,7 +61,7 @@ public: ~ModelManagerSupportClang(); CppTools::CppCompletionAssistProvider *completionAssistProvider() override; - CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor( + CppTools::BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) override; CppTools::FollowSymbolInterface &followSymbolInterface() override; CppTools::RefactoringEngineInterface &refactoringEngineInterface() override; diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index f168f1810b3..3fcbda6a1ee 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -394,7 +394,7 @@ const MinimizableInfoBars &CppEditorDocument::minimizableInfoBars() const CppTools::BaseEditorDocumentProcessor *CppEditorDocument::processor() { if (!m_processor) { - m_processor.reset(mm()->editorDocumentProcessor(this)); + m_processor.reset(mm()->createEditorDocumentProcessor(this)); connect(m_processor.data(), &CppTools::BaseEditorDocumentProcessor::projectPartInfoUpdated, [this] (const CppTools::ProjectPartInfo &info) { diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index ad255459b2c..9beb97b2f36 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -1293,10 +1293,10 @@ CppCompletionAssistProvider *CppModelManager::completionAssistProvider() const return d->m_activeModelManagerSupport->completionAssistProvider(); } -BaseEditorDocumentProcessor *CppModelManager::editorDocumentProcessor( +BaseEditorDocumentProcessor *CppModelManager::createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) const { - return d->m_activeModelManagerSupport->editorDocumentProcessor(baseTextDocument); + return d->m_activeModelManagerSupport->createEditorDocumentProcessor(baseTextDocument); } void CppModelManager::setIndexingSupport(CppIndexingSupport *indexingSupport) diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 3eb06eca653..bf05c26156d 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -172,7 +172,7 @@ public: void activateClangCodeModel(ModelManagerSupportProvider *modelManagerSupportProvider); CppCompletionAssistProvider *completionAssistProvider() const; - BaseEditorDocumentProcessor *editorDocumentProcessor( + BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) const; FollowSymbolInterface &followSymbolInterface() const; diff --git a/src/plugins/cpptools/cppmodelmanagersupport.h b/src/plugins/cpptools/cppmodelmanagersupport.h index b1256aa51fa..306f1aa974f 100644 --- a/src/plugins/cpptools/cppmodelmanagersupport.h +++ b/src/plugins/cpptools/cppmodelmanagersupport.h @@ -48,7 +48,7 @@ public: virtual ~ModelManagerSupport() = 0; virtual CppCompletionAssistProvider *completionAssistProvider() = 0; - virtual BaseEditorDocumentProcessor *editorDocumentProcessor( + virtual BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) = 0; virtual FollowSymbolInterface &followSymbolInterface() = 0; virtual RefactoringEngineInterface &refactoringEngineInterface() = 0; diff --git a/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp b/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp index 95b98bbdf38..2dfc34dbab0 100644 --- a/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp +++ b/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp @@ -63,7 +63,7 @@ ModelManagerSupportInternal::~ModelManagerSupportInternal() { } -BaseEditorDocumentProcessor *ModelManagerSupportInternal::editorDocumentProcessor( +BaseEditorDocumentProcessor *ModelManagerSupportInternal::createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) { return new BuiltinEditorDocumentProcessor(baseTextDocument); diff --git a/src/plugins/cpptools/cppmodelmanagersupportinternal.h b/src/plugins/cpptools/cppmodelmanagersupportinternal.h index 6ac2d4d022c..70b56f43516 100644 --- a/src/plugins/cpptools/cppmodelmanagersupportinternal.h +++ b/src/plugins/cpptools/cppmodelmanagersupportinternal.h @@ -41,7 +41,7 @@ public: virtual ~ModelManagerSupportInternal(); CppCompletionAssistProvider *completionAssistProvider() final; - BaseEditorDocumentProcessor *editorDocumentProcessor( + BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) final; FollowSymbolInterface &followSymbolInterface() final; RefactoringEngineInterface &refactoringEngineInterface() final; From 5e861d2be6729b7d4b0927b1d334f6298927013e Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 11 Jan 2018 17:06:26 +0100 Subject: [PATCH 08/16] CppTools: Move CppHoverHandler to CppTools This is in preparation for clang code model to provide its own hover handler. Change-Id: Ifbdd96f427989bd5d1fbc4badb9c38108485c2f2 Reviewed-by: Ivan Donchevskii --- .../clangcodemodel/clangmodelmanagersupport.cpp | 6 ++++++ .../clangcodemodel/clangmodelmanagersupport.h | 1 + src/plugins/cppeditor/cppeditor.pro | 4 ---- src/plugins/cppeditor/cppeditor.qbs | 4 ---- src/plugins/cppeditor/cppeditorplugin.cpp | 9 ++++++--- src/plugins/cppeditor/cppincludehierarchy.cpp | 2 +- src/plugins/cppeditor/cpptypehierarchy.cpp | 3 ++- src/plugins/cppeditor/cpptypehierarchy.h | 7 ++++--- .../followsymbol_switchmethoddecldef_test.cpp | 2 +- .../cppelementevaluator.cpp | 6 ++---- .../cppelementevaluator.h | 16 +++++++--------- .../{cppeditor => cpptools}/cpphoverhandler.cpp | 7 ++----- .../{cppeditor => cpptools}/cpphoverhandler.h | 10 +++++----- src/plugins/cpptools/cppmodelmanager.cpp | 7 ++++++- src/plugins/cpptools/cppmodelmanager.h | 8 ++++++-- src/plugins/cpptools/cppmodelmanagersupport.h | 6 +++++- .../cpptools/cppmodelmanagersupportinternal.cpp | 6 ++++++ .../cpptools/cppmodelmanagersupportinternal.h | 1 + src/plugins/cpptools/cpptools.pro | 4 ++++ src/plugins/cpptools/cpptools.qbs | 4 ++++ 20 files changed, 69 insertions(+), 44 deletions(-) rename src/plugins/{cppeditor => cpptools}/cppelementevaluator.cpp (99%) rename src/plugins/{cppeditor => cpptools}/cppelementevaluator.h (96%) rename src/plugins/{cppeditor => cpptools}/cpphoverhandler.cpp (98%) rename src/plugins/{cppeditor => cpptools}/cpphoverhandler.h (91%) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index f66392d64ef..9271975dfde 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -111,6 +112,11 @@ CppTools::CppCompletionAssistProvider *ModelManagerSupportClang::completionAssis return &m_completionAssistProvider; } +TextEditor::BaseHoverHandler *ModelManagerSupportClang::createHoverHandler() +{ + return new CppTools::CppHoverHandler; +} + CppTools::FollowSymbolInterface &ModelManagerSupportClang::followSymbolInterface() { return *m_followSymbol; diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index 842c1d75fa2..92f253c5a8b 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -61,6 +61,7 @@ public: ~ModelManagerSupportClang(); CppTools::CppCompletionAssistProvider *completionAssistProvider() override; + TextEditor::BaseHoverHandler *createHoverHandler() override; CppTools::BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) override; CppTools::FollowSymbolInterface &followSymbolInterface() override; diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro index 0bc3391ce81..74b1daf63b3 100644 --- a/src/plugins/cppeditor/cppeditor.pro +++ b/src/plugins/cppeditor/cppeditor.pro @@ -12,10 +12,8 @@ HEADERS += \ cppeditorenums.h \ cppeditorplugin.h \ cppeditorwidget.h \ - cppelementevaluator.h \ cppfunctiondecldeflink.h \ cpphighlighter.h \ - cpphoverhandler.h \ cppparsecontext.h \ cppincludehierarchy.h \ cppinsertvirtualmethods.h \ @@ -38,10 +36,8 @@ SOURCES += \ cppeditordocument.cpp \ cppeditorplugin.cpp \ cppeditorwidget.cpp \ - cppelementevaluator.cpp \ cppfunctiondecldeflink.cpp \ cpphighlighter.cpp \ - cpphoverhandler.cpp \ cppparsecontext.cpp \ cppincludehierarchy.cpp \ cppinsertvirtualmethods.cpp \ diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index 5d8b17adb41..5a44f175eb2 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -39,14 +39,10 @@ QtcPlugin { "cppeditorenums.h", "cppeditorplugin.cpp", "cppeditorplugin.h", - "cppelementevaluator.cpp", - "cppelementevaluator.h", "cppfunctiondecldeflink.cpp", "cppfunctiondecldeflink.h", "cpphighlighter.cpp", "cpphighlighter.h", - "cpphoverhandler.cpp", - "cpphoverhandler.h", "cppincludehierarchy.cpp", "cppincludehierarchy.h", "cppinsertvirtualmethods.cpp", diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 3f352f1ffe8..27cbf4827e5 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -31,7 +31,6 @@ #include "cppeditorwidget.h" #include "cppeditordocument.h" #include "cpphighlighter.h" -#include "cpphoverhandler.h" #include "cppincludehierarchy.h" #include "cppoutline.h" #include "cppquickfixassistant.h" @@ -53,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -105,7 +105,7 @@ public: | TextEditorActionHandler::UnCollapseAll | TextEditorActionHandler::FollowSymbolUnderCursor); - addHoverHandler(new CppHoverHandler); + addHoverHandler(CppModelManager::instance()->createHoverHandler()); addHoverHandler(new ColorPreviewHoverHandler); addHoverHandler(new ResourcePreviewHoverHandler); } @@ -145,7 +145,6 @@ bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err { Q_UNUSED(errorMessage) - addAutoReleasedObject(new CppEditorFactory); addAutoReleasedObject(new CppOutlineWidgetFactory); addAutoReleasedObject(new CppTypeHierarchyFactory); addAutoReleasedObject(new CppIncludeHierarchyFactory); @@ -268,6 +267,10 @@ bool CppEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err void CppEditorPlugin::extensionsInitialized() { + // Add the editor factory here instead of in initialize() + // so that the Clang Code Model has a chance to hook in. + addAutoReleasedObject(new CppEditorFactory); + if (!HostOsInfo::isMacHost() && !HostOsInfo::isWindowsHost()) { FileIconProvider::registerIconOverlayForMimeType( QIcon(creatorTheme()->imageFile(Theme::IconOverlayCppSource, QLatin1String(":/cppeditor/images/qt_cpp.png"))), diff --git a/src/plugins/cppeditor/cppincludehierarchy.cpp b/src/plugins/cppeditor/cppincludehierarchy.cpp index 1f5f089181c..22bebf3dafa 100644 --- a/src/plugins/cppeditor/cppincludehierarchy.cpp +++ b/src/plugins/cppeditor/cppincludehierarchy.cpp @@ -29,13 +29,13 @@ #include "cppeditorwidget.h" #include "cppeditorconstants.h" #include "cppeditorplugin.h" -#include "cppelementevaluator.h" #include #include #include #include +#include #include #include #include diff --git a/src/plugins/cppeditor/cpptypehierarchy.cpp b/src/plugins/cppeditor/cpptypehierarchy.cpp index 54eaaf2f57c..0b3198d4c9f 100644 --- a/src/plugins/cppeditor/cpptypehierarchy.cpp +++ b/src/plugins/cppeditor/cpptypehierarchy.cpp @@ -28,11 +28,11 @@ #include "cppeditorconstants.h" #include "cppeditor.h" #include "cppeditorwidget.h" -#include "cppelementevaluator.h" #include "cppeditorplugin.h" #include #include +#include #include #include #include @@ -46,6 +46,7 @@ #include using namespace CppEditor; +using namespace CppTools; using namespace CppEditor::Internal; using namespace Utils; diff --git a/src/plugins/cppeditor/cpptypehierarchy.h b/src/plugins/cppeditor/cpptypehierarchy.h index 355f87065d9..e99d8a180e8 100644 --- a/src/plugins/cppeditor/cpptypehierarchy.h +++ b/src/plugins/cppeditor/cpptypehierarchy.h @@ -47,11 +47,12 @@ class NavigationTreeView; class AnnotatedItemDelegate; } +namespace CppTools { class CppClass; } + namespace CppEditor { namespace Internal { class CppEditorWidget; -class CppClass; class CppTypeHierarchyModel : public QStandardItemModel { @@ -75,8 +76,8 @@ public: void perform(); private: - typedef QList CppClass::*HierarchyMember; - void buildHierarchy(const CppClass &cppClass, QStandardItem *parent, + typedef QList CppTools::CppClass::*HierarchyMember; + void buildHierarchy(const CppTools::CppClass &cppClass, QStandardItem *parent, bool isRoot, HierarchyMember member); void showNoTypeHierarchyLabel(); void showTypeHierarchy(); diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 1f7576c49b1..ef025a61795 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -27,8 +27,8 @@ #include "cppeditorwidget.h" #include "cppeditorplugin.h" #include "cppeditortestcase.h" -#include "cppelementevaluator.h" +#include #include #include #include diff --git a/src/plugins/cppeditor/cppelementevaluator.cpp b/src/plugins/cpptools/cppelementevaluator.cpp similarity index 99% rename from src/plugins/cppeditor/cppelementevaluator.cpp rename to src/plugins/cpptools/cppelementevaluator.cpp index 1e95850a18a..3281783ef26 100644 --- a/src/plugins/cppeditor/cppelementevaluator.cpp +++ b/src/plugins/cpptools/cppelementevaluator.cpp @@ -42,8 +42,7 @@ using namespace CPlusPlus; -namespace CppEditor { -namespace Internal { +namespace CppTools { static QStringList stripName(const QString &name) { @@ -471,5 +470,4 @@ CppEnumerator::CppEnumerator(EnumeratorDeclaration *declaration) tooltip.append(QLatin1String(" = ") + enumeratorValue); } -} // namespace Internal -} // namespace CppEditor +} // namespace CppTools diff --git a/src/plugins/cppeditor/cppelementevaluator.h b/src/plugins/cpptools/cppelementevaluator.h similarity index 96% rename from src/plugins/cppeditor/cppelementevaluator.h rename to src/plugins/cpptools/cppelementevaluator.h index 91ef68e2d89..af994989edc 100644 --- a/src/plugins/cppeditor/cppelementevaluator.h +++ b/src/plugins/cpptools/cppelementevaluator.h @@ -25,6 +25,8 @@ #pragma once +#include "cpptools_global.h" + #include #include @@ -41,14 +43,11 @@ class LookupItem; class LookupContext; } -namespace CppTools { class CppModelManager; } - -namespace CppEditor { -namespace Internal { - +namespace CppTools { class CppElement; +class CppModelManager; -class CppElementEvaluator +class CPPTOOLS_EXPORT CppElementEvaluator { public: explicit CppElementEvaluator(TextEditor::TextEditorWidget *editor); @@ -82,7 +81,7 @@ private: QString m_diagnosis; }; -class CppElement +class CPPTOOLS_EXPORT CppElement { protected: CppElement(); @@ -189,5 +188,4 @@ public: explicit CppEnumerator(CPlusPlus::EnumeratorDeclaration *declaration); }; -} // namespace Internal -} // namespace CppEditor +} // namespace CppTools diff --git a/src/plugins/cppeditor/cpphoverhandler.cpp b/src/plugins/cpptools/cpphoverhandler.cpp similarity index 98% rename from src/plugins/cppeditor/cpphoverhandler.cpp rename to src/plugins/cpptools/cpphoverhandler.cpp index d480c12c61b..d01102f4f2b 100644 --- a/src/plugins/cppeditor/cpphoverhandler.cpp +++ b/src/plugins/cpptools/cpphoverhandler.cpp @@ -25,7 +25,6 @@ #include "cpphoverhandler.h" -#include "cppeditorconstants.h" #include "cppelementevaluator.h" #include @@ -89,8 +88,7 @@ void processWithEditorDocumentProcessor(TextEditorWidget *editorWidget, } // anonymous namespace -namespace CppEditor { -namespace Internal { +namespace CppTools { void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos) { @@ -186,5 +184,4 @@ void CppHoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidget, helpId); } -} // namespace Internal -} // namespace CppEditor +} // namespace CppTools diff --git a/src/plugins/cppeditor/cpphoverhandler.h b/src/plugins/cpptools/cpphoverhandler.h similarity index 91% rename from src/plugins/cppeditor/cpphoverhandler.h rename to src/plugins/cpptools/cpphoverhandler.h index accc2751523..b728b970fe4 100644 --- a/src/plugins/cppeditor/cpphoverhandler.h +++ b/src/plugins/cpptools/cpphoverhandler.h @@ -25,12 +25,13 @@ #pragma once +#include "cpptools_global.h" + #include -namespace CppEditor { -namespace Internal { +namespace CppTools { -class CppHoverHandler : public TextEditor::BaseHoverHandler +class CPPTOOLS_EXPORT CppHoverHandler : public TextEditor::BaseHoverHandler { private: void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override; @@ -41,5 +42,4 @@ private: int m_positionForEditorDocumentProcessor = -1; }; -} // namespace Internal -} // namespace CppEditor +} // namespace CppTools diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 9beb97b2f36..f1b1d2c2bd0 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -1293,8 +1293,13 @@ CppCompletionAssistProvider *CppModelManager::completionAssistProvider() const return d->m_activeModelManagerSupport->completionAssistProvider(); } +TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const +{ + return d->m_activeModelManagerSupport->createHoverHandler(); +} + BaseEditorDocumentProcessor *CppModelManager::createEditorDocumentProcessor( - TextEditor::TextDocument *baseTextDocument) const + TextEditor::TextDocument *baseTextDocument) const { return d->m_activeModelManagerSupport->createEditorDocumentProcessor(baseTextDocument); } diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index bf05c26156d..d8b8d2f1922 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -44,7 +44,10 @@ class IEditor; } namespace CPlusPlus { class LookupContext; } namespace ProjectExplorer { class Project; } -namespace TextEditor { class TextDocument; } +namespace TextEditor { +class BaseHoverHandler; +class TextDocument; +} // namespace TextEditor namespace CppTools { @@ -173,7 +176,8 @@ public: void activateClangCodeModel(ModelManagerSupportProvider *modelManagerSupportProvider); CppCompletionAssistProvider *completionAssistProvider() const; BaseEditorDocumentProcessor *createEditorDocumentProcessor( - TextEditor::TextDocument *baseTextDocument) const; + TextEditor::TextDocument *baseTextDocument) const; + TextEditor::BaseHoverHandler *createHoverHandler() const; FollowSymbolInterface &followSymbolInterface() const; void setIndexingSupport(CppIndexingSupport *indexingSupport); diff --git a/src/plugins/cpptools/cppmodelmanagersupport.h b/src/plugins/cpptools/cppmodelmanagersupport.h index 306f1aa974f..06102f6007f 100644 --- a/src/plugins/cpptools/cppmodelmanagersupport.h +++ b/src/plugins/cpptools/cppmodelmanagersupport.h @@ -30,7 +30,10 @@ #include #include -namespace TextEditor { class TextDocument; } +namespace TextEditor { +class TextDocument; +class BaseHoverHandler; +} // namespace TextEditor namespace CppTools { @@ -48,6 +51,7 @@ public: virtual ~ModelManagerSupport() = 0; virtual CppCompletionAssistProvider *completionAssistProvider() = 0; + virtual TextEditor::BaseHoverHandler *createHoverHandler() = 0; virtual BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) = 0; virtual FollowSymbolInterface &followSymbolInterface() = 0; diff --git a/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp b/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp index 2dfc34dbab0..51919955549 100644 --- a/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp +++ b/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp @@ -26,6 +26,7 @@ #include "cppcompletionassist.h" #include "cppmodelmanagersupportinternal.h" #include "cppfollowsymbolundercursor.h" +#include "cpphoverhandler.h" #include "cpprefactoringengine.h" #include "builtineditordocumentprocessor.h" @@ -74,6 +75,11 @@ CppCompletionAssistProvider *ModelManagerSupportInternal::completionAssistProvid return m_completionAssistProvider.data(); } +TextEditor::BaseHoverHandler *ModelManagerSupportInternal::createHoverHandler() +{ + return new CppHoverHandler; +} + FollowSymbolInterface &ModelManagerSupportInternal::followSymbolInterface() { return *m_followSymbol; diff --git a/src/plugins/cpptools/cppmodelmanagersupportinternal.h b/src/plugins/cpptools/cppmodelmanagersupportinternal.h index 70b56f43516..e2954792ea4 100644 --- a/src/plugins/cpptools/cppmodelmanagersupportinternal.h +++ b/src/plugins/cpptools/cppmodelmanagersupportinternal.h @@ -41,6 +41,7 @@ public: virtual ~ModelManagerSupportInternal(); CppCompletionAssistProvider *completionAssistProvider() final; + TextEditor::BaseHoverHandler *createHoverHandler() final; BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) final; FollowSymbolInterface &followSymbolInterface() final; diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 4dfc0ceeced..e16e3ec0bcd 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -32,11 +32,13 @@ HEADERS += \ cppdoxygen.h \ cppeditoroutline.h \ cppeditorwidgetinterface.h \ + cppelementevaluator.h \ cppfileiterationorder.h \ cppfilesettingspage.h \ cppfindreferences.h \ cppfollowsymbolundercursor.h \ cppfunctionsfilter.h \ + cpphoverhandler.h \ cppincludesfilter.h \ cppindexingsupport.h \ cpplocalsymbols.h \ @@ -125,11 +127,13 @@ SOURCES += \ cppcurrentdocumentfilter.cpp \ cppeditoroutline.cpp \ cppdoxygen.cpp \ + cppelementevaluator.cpp \ cppfileiterationorder.cpp \ cppfilesettingspage.cpp \ cppfindreferences.cpp \ cppfollowsymbolundercursor.cpp \ cppfunctionsfilter.cpp \ + cpphoverhandler.cpp \ cppincludesfilter.cpp \ cppindexingsupport.cpp \ cpplocalsymbols.cpp \ diff --git a/src/plugins/cpptools/cpptools.qbs b/src/plugins/cpptools/cpptools.qbs index a510f5a21d6..a258ce18a30 100644 --- a/src/plugins/cpptools/cpptools.qbs +++ b/src/plugins/cpptools/cpptools.qbs @@ -90,6 +90,8 @@ Project { "cppeditoroutline.cpp", "cppeditoroutline.h", "cppeditorwidgetinterface.h", + "cppelementevaluator.cpp", + "cppelementevaluator.h", "cppfileiterationorder.cpp", "cppfileiterationorder.h", "cppfilesettingspage.cpp", @@ -101,6 +103,8 @@ Project { "cppfollowsymbolundercursor.h", "cppfunctionsfilter.cpp", "cppfunctionsfilter.h", + "cpphoverhandler.cpp", + "cpphoverhandler.h", "cppincludesfilter.cpp", "cppincludesfilter.h", "cppindexingsupport.cpp", From d7409e01a7a0e89affe7bd483b98e921a62f4037 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 12 Jan 2018 14:35:27 +0100 Subject: [PATCH 09/16] CppTools: Fix showing main help sentence in tooltip Mouse hover on e.g. "QString" is supposed to show QString The QString class provides... The sentence was removed unintentionally by commit a7e8406ced48818682e52ca208af94c18c8c837e TextEditor: Remove unneeded functions in BaseHoverHandler Change-Id: I356e66c0c21c528822c0f2e37f8058fa7b7d89bf Reviewed-by: David Schulz --- src/plugins/cpptools/cpphoverhandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cpptools/cpphoverhandler.cpp b/src/plugins/cpptools/cpphoverhandler.cpp index d01102f4f2b..9b9a8edff74 100644 --- a/src/plugins/cpptools/cpphoverhandler.cpp +++ b/src/plugins/cpptools/cpphoverhandler.cpp @@ -141,7 +141,7 @@ void CppHoverHandler::decorateToolTip() if (Qt::mightBeRichText(toolTip())) setToolTip(toolTip().toHtmlEscaped()); - if (priority() != Priority_Diagnostic) + if (priority() == Priority_Diagnostic) return; const HelpItem &help = lastHelpItemIdentified(); From 61b5bbc8e92d0e81e542dcac69eb3b27fc62fb5b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 15 Jan 2018 12:52:32 +0100 Subject: [PATCH 10/16] Qbs build: Fix that copyright was not adapted in Info.plist Change-Id: Ie5670a4a420f34dbef6cbb204063e8921eafd82b Reviewed-by: Jake Petroules --- qbs/modules/qtc/qtc.qbs | 1 + src/app/app.qbs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 4b4796e63a7..23acac180e1 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -18,6 +18,7 @@ Module { + ide_compat_version_minor + '.' + ide_compat_version_release property string qtcreator_copyright_year: '2017' + property string qtcreator_copyright_string: "(C) " + qtcreator_copyright_year + " The Qt Company Ltd" property string ide_display_name: 'Qt Creator' property string ide_id: 'qtcreator' diff --git a/src/app/app.qbs b/src/app/app.qbs index 7d9b7ab91c4..9fcbd22099e 100644 --- a/src/app/app.qbs +++ b/src/app/app.qbs @@ -26,6 +26,10 @@ QtcProduct { installSourceBase: isBundle ? buildDirectory : base property bool qtcRunnable: true + bundle.infoPlist: ({ + "NSHumanReadableCopyright": qtc.qtcreator_copyright_string + }) + cpp.rpaths: qbs.targetOS.contains("macos") ? ["@executable_path/../Frameworks"] : ["$ORIGIN/../" + qtc.libDirName + "/qtcreator"] cpp.includePaths: [ From 7872ddde4cbaba2c6e5f55f1d05184ba33ba326b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 11 Jan 2018 15:59:11 +0100 Subject: [PATCH 11/16] Make executable name configurable Change-Id: I6b5420ab2275c37e51f665005e31b80b6dfae8cb Reviewed-by: Jake Petroules --- qbs/modules/qtc/qtc.qbs | 3 ++- qtcreator.pri | 12 +++++++----- src/app/app-Info.plist | 4 ++-- src/app/app.pro | 1 + src/app/app.qbs | 1 + 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 23acac180e1..0177c205643 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -23,10 +23,11 @@ Module { property string ide_display_name: 'Qt Creator' property string ide_id: 'qtcreator' property string ide_cased_id: 'QtCreator' + property string ide_bundle_identifier: 'org.qt-project.qtcreator' property string libDirName: "lib" property string ide_app_path: qbs.targetOS.contains("macos") ? "" : "bin" - property string ide_app_target: qbs.targetOS.contains("macos") ? "Qt Creator" : "qtcreator" + property string ide_app_target: qbs.targetOS.contains("macos") ? ide_display_name : ide_id property string ide_library_path: { if (qbs.targetOS.contains("macos")) return ide_app_target + ".app/Contents/Frameworks" diff --git a/qtcreator.pri b/qtcreator.pri index 09557fe15fd..8ef4e06e2b0 100644 --- a/qtcreator.pri +++ b/qtcreator.pri @@ -8,9 +8,11 @@ QTCREATOR_DISPLAY_VERSION = 4.6.0-beta1 QTCREATOR_COPYRIGHT_YEAR = 2017 BINARY_ARTIFACTS_BRANCH = master -isEmpty(IDE_DISPLAY_NAME): IDE_DISPLAY_NAME = Qt Creator -isEmpty(IDE_ID): IDE_ID = qtcreator -isEmpty(IDE_CASED_ID): IDE_CASED_ID = QtCreator +isEmpty(IDE_DISPLAY_NAME): IDE_DISPLAY_NAME = Qt Creator +isEmpty(IDE_ID): IDE_ID = qtcreator +isEmpty(IDE_CASED_ID): IDE_CASED_ID = QtCreator + +isEmpty(PRODUCT_BUNDLE_IDENTIFIER): PRODUCT_BUNDLE_IDENTIFIER = org.qt-project.$$IDE_ID CONFIG += c++14 @@ -100,7 +102,7 @@ isEmpty(IDE_BUILD_TREE) { IDE_APP_PATH = $$IDE_BUILD_TREE/bin osx { - IDE_APP_TARGET = "Qt Creator" + IDE_APP_TARGET = "$$IDE_DISPLAY_NAME" # check if IDE_BUILD_TREE is actually an existing Qt Creator.app, # for building against a binary package @@ -130,7 +132,7 @@ osx { INSTALL_APP_PATH = $$QTC_PREFIX/ } else { contains(TEMPLATE, vc.*):vcproj = 1 - IDE_APP_TARGET = qtcreator + IDE_APP_TARGET = $$IDE_ID # target output path if not set manually isEmpty(IDE_OUTPUT_PATH): IDE_OUTPUT_PATH = $$IDE_BUILD_TREE diff --git a/src/app/app-Info.plist b/src/app/app-Info.plist index 8940f2bd9ab..91104f163d5 100644 --- a/src/app/app-Info.plist +++ b/src/app/app-Info.plist @@ -245,9 +245,9 @@ CFBundleSignature ???? CFBundleExecutable - Qt Creator + @EXECUTABLE@ CFBundleIdentifier - org.qt-project.qtcreator + @PRODUCT_BUNDLE_IDENTIFIER@ CFBundleVersion @FULL_VERSION@ CFBundleShortVersionString diff --git a/src/app/app.pro b/src/app/app.pro index f8abf4d7659..a64c357020d 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -62,6 +62,7 @@ win32 { infoplist = $$cat($$PWD/app-Info.plist, blob) infoplist = $$replace(infoplist, @MACOSX_DEPLOYMENT_TARGET@, $$QMAKE_MACOSX_DEPLOYMENT_TARGET) infoplist = $$replace(infoplist, @QTCREATOR_COPYRIGHT_YEAR@, $$QTCREATOR_COPYRIGHT_YEAR) + infoplist = $$replace(infoplist, @PRODUCT_BUNDLE_IDENTIFIER@, $$PRODUCT_BUNDLE_IDENTIFIER) write_file($$OUT_PWD/Info.plist, infoplist) QMAKE_INFO_PLIST = $$OUT_PWD/Info.plist diff --git a/src/app/app.qbs b/src/app/app.qbs index 9fcbd22099e..782796459fd 100644 --- a/src/app/app.qbs +++ b/src/app/app.qbs @@ -26,6 +26,7 @@ QtcProduct { installSourceBase: isBundle ? buildDirectory : base property bool qtcRunnable: true + bundle.identifier: qtc.ide_bundle_identifier bundle.infoPlist: ({ "NSHumanReadableCopyright": qtc.qtcreator_copyright_string }) From 76c25bcd6a97dda3921e8bc487e1c61f10938ad2 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 12 Jan 2018 12:29:43 +0100 Subject: [PATCH 12/16] Clang: Provide tooltips This includes also the query data for the help system (F1) for an identifier under cursor. Regressions (libclang changes necessary): - Function signatures do not contain default values. - Aliases are not resolved for/at: - template types - qualified name of a type Fixes/Improvements: - Resolve "auto" - On a template type, show also the template parameter. - For a typedef like typedef long long superlong; the tooltip was "long long superlong", which was confusing. Now, "long long" is shown. New: - Show first or \brief paragraph of a documentation comment. - Show size of a class at definition. - Show size of a field member in class definition. Task-number: QTCREATORBUG-11259 Change-Id: Ie1a07930d0e882015d07dc43e35bb81a685cdeb8 Reviewed-by: Marco Bubke --- .../clangcodemodelclientinterface.cpp | 3 + .../clangcodemodelclientinterface.h | 3 + .../clangcodemodelclientmessages.h | 1 + .../clangcodemodelclientproxy.cpp | 5 + .../clangsupport/clangcodemodelclientproxy.h | 1 + .../clangcodemodelserverinterface.cpp | 3 + .../clangcodemodelserverinterface.h | 1 + .../clangcodemodelservermessages.h | 1 + .../clangcodemodelserverproxy.cpp | 5 + .../clangsupport/clangcodemodelserverproxy.h | 1 + src/libs/clangsupport/clangsupport-lib.pri | 6 + src/libs/clangsupport/clangsupport_global.h | 3 + src/libs/clangsupport/filecontainer.cpp | 3 +- src/libs/clangsupport/filecontainer.h | 12 +- src/libs/clangsupport/messageenvelop.cpp | 6 + .../clangsupport/requesttooltipmessage.cpp | 48 ++ src/libs/clangsupport/requesttooltipmessage.h | 94 +++ src/libs/clangsupport/tooltipinfo.cpp | 65 ++ src/libs/clangsupport/tooltipinfo.h | 124 ++++ src/libs/clangsupport/tooltipmessage.cpp | 44 ++ src/libs/clangsupport/tooltipmessage.h | 87 +++ src/libs/sqlite/utf8string.h | 3 +- .../clangbackendcommunicator.cpp | 9 + .../clangcodemodel/clangbackendcommunicator.h | 3 + .../clangcodemodel/clangbackendreceiver.cpp | 78 +++ .../clangcodemodel/clangbackendreceiver.h | 5 +- .../clangcodemodel/clangbackendsender.cpp | 7 + .../clangcodemodel/clangbackendsender.h | 1 + src/plugins/clangcodemodel/clangcodemodel.pro | 2 + src/plugins/clangcodemodel/clangcodemodel.qbs | 2 + .../clangeditordocumentprocessor.cpp | 19 +- .../clangeditordocumentprocessor.h | 5 +- .../clangcodemodel/clanghoverhandler.cpp | 232 +++++++ .../clangcodemodel/clanghoverhandler.h | 60 ++ .../clangmodelmanagersupport.cpp | 4 +- .../cpptools/baseeditordocumentprocessor.cpp | 7 + .../cpptools/baseeditordocumentprocessor.h | 14 + src/plugins/cpptools/cpphoverhandler.cpp | 126 +--- src/plugins/cpptools/cpphoverhandler.h | 7 +- src/plugins/texteditor/texteditor.cpp | 2 + .../clangbackend/source/clangbackend_global.h | 5 + .../source/clangbackendclangipc-source.pri | 4 + .../source/clangcodemodelserver.cpp | 20 + .../source/clangcodemodelserver.h | 1 + .../clangbackend/source/clangjobrequest.cpp | 15 +- .../clangbackend/source/clangjobrequest.h | 2 + .../source/clangrequesttooltipjob.cpp | 67 ++ .../source/clangrequesttooltipjob.h | 43 ++ .../source/clangtooltipinfocollector.cpp | 531 +++++++++++++++ .../source/clangtooltipinfocollector.h | 45 ++ .../source/clangtranslationunit.cpp | 15 + .../source/clangtranslationunit.h | 5 + src/tools/clangbackend/source/clangtype.cpp | 97 +++ src/tools/clangbackend/source/clangtype.h | 4 + src/tools/clangbackend/source/cursor.cpp | 38 ++ src/tools/clangbackend/source/cursor.h | 11 +- src/tools/clangbackend/source/unsavedfile.cpp | 21 + src/tools/clangbackend/source/unsavedfile.h | 1 + .../echoserver/echoclangcodemodelserver.cpp | 5 + .../echoserver/echoclangcodemodelserver.h | 1 + tests/unit/unittest/clangtooltipinfo-test.cpp | 628 ++++++++++++++++++ .../unittest/conditionally-disabled-tests.h | 6 + tests/unit/unittest/data/tooltipinfo.cpp | 180 +++++ tests/unit/unittest/data/tooltipinfo.h | 3 + tests/unit/unittest/dummyclangipcclient.h | 1 + .../unit/unittest/gtest-creator-printing.cpp | 46 +- tests/unit/unittest/gtest-creator-printing.h | 6 + .../unit/unittest/mockclangcodemodelclient.h | 2 + .../unit/unittest/mockclangcodemodelserver.h | 2 + tests/unit/unittest/unittest.pro | 1 + tests/unit/unittest/unsavedfile-test.cpp | 28 + 71 files changed, 2824 insertions(+), 112 deletions(-) create mode 100644 src/libs/clangsupport/requesttooltipmessage.cpp create mode 100644 src/libs/clangsupport/requesttooltipmessage.h create mode 100644 src/libs/clangsupport/tooltipinfo.cpp create mode 100644 src/libs/clangsupport/tooltipinfo.h create mode 100644 src/libs/clangsupport/tooltipmessage.cpp create mode 100644 src/libs/clangsupport/tooltipmessage.h create mode 100644 src/plugins/clangcodemodel/clanghoverhandler.cpp create mode 100644 src/plugins/clangcodemodel/clanghoverhandler.h create mode 100644 src/tools/clangbackend/source/clangrequesttooltipjob.cpp create mode 100644 src/tools/clangbackend/source/clangrequesttooltipjob.h create mode 100644 src/tools/clangbackend/source/clangtooltipinfocollector.cpp create mode 100644 src/tools/clangbackend/source/clangtooltipinfocollector.h create mode 100644 tests/unit/unittest/clangtooltipinfo-test.cpp create mode 100644 tests/unit/unittest/data/tooltipinfo.cpp create mode 100644 tests/unit/unittest/data/tooltipinfo.h diff --git a/src/libs/clangsupport/clangcodemodelclientinterface.cpp b/src/libs/clangsupport/clangcodemodelclientinterface.cpp index 0de9f39044a..492ea7896fe 100644 --- a/src/libs/clangsupport/clangcodemodelclientinterface.cpp +++ b/src/libs/clangsupport/clangcodemodelclientinterface.cpp @@ -53,6 +53,9 @@ void ClangCodeModelClientInterface::dispatch(const MessageEnvelop &messageEnvelo case MessageType::FollowSymbolMessage: followSymbol(messageEnvelop.message()); break; + case MessageType::ToolTipMessage: + tooltip(messageEnvelop.message()); + break; default: qWarning() << "Unknown ClangCodeModelClientMessage"; } diff --git a/src/libs/clangsupport/clangcodemodelclientinterface.h b/src/libs/clangsupport/clangcodemodelclientinterface.h index b6b878baaf0..6e8f3dd2485 100644 --- a/src/libs/clangsupport/clangcodemodelclientinterface.h +++ b/src/libs/clangsupport/clangcodemodelclientinterface.h @@ -43,6 +43,8 @@ class RegisterUnsavedFilesForEditorMessage; class RequestDocumentAnnotationsMessage; class RequestReferencesMessage; class RequestFollowSymbolMessage; +class RequestToolTipMessage; +class ToolTipMessage; class UnregisterProjectPartsForEditorMessage; class UnregisterTranslationUnitsForEditorMessage; class UnregisterUnsavedFilesForEditorMessage; @@ -60,6 +62,7 @@ public: virtual void documentAnnotationsChanged(const DocumentAnnotationsChangedMessage &message) = 0; virtual void references(const ReferencesMessage &message) = 0; virtual void followSymbol(const FollowSymbolMessage &message) = 0; + virtual void tooltip(const ToolTipMessage &message) = 0; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/clangcodemodelclientmessages.h b/src/libs/clangsupport/clangcodemodelclientmessages.h index 5b5c9b42edb..2903cda2079 100644 --- a/src/libs/clangsupport/clangcodemodelclientmessages.h +++ b/src/libs/clangsupport/clangcodemodelclientmessages.h @@ -31,3 +31,4 @@ #include "documentannotationschangedmessage.h" #include "referencesmessage.h" #include "followsymbolmessage.h" +#include "tooltipmessage.h" diff --git a/src/libs/clangsupport/clangcodemodelclientproxy.cpp b/src/libs/clangsupport/clangcodemodelclientproxy.cpp index 6a285c23668..fc75a226ed5 100644 --- a/src/libs/clangsupport/clangcodemodelclientproxy.cpp +++ b/src/libs/clangsupport/clangcodemodelclientproxy.cpp @@ -95,6 +95,11 @@ void ClangCodeModelClientProxy::followSymbol(const FollowSymbolMessage &message) m_writeMessageBlock.write(message); } +void ClangCodeModelClientProxy::tooltip(const ToolTipMessage &message) +{ + m_writeMessageBlock.write(message); +} + void ClangCodeModelClientProxy::readMessages() { for (const MessageEnvelop &message : m_readMessageBlock.readAll()) diff --git a/src/libs/clangsupport/clangcodemodelclientproxy.h b/src/libs/clangsupport/clangcodemodelclientproxy.h index 0665d6e8faa..58b87a05d8b 100644 --- a/src/libs/clangsupport/clangcodemodelclientproxy.h +++ b/src/libs/clangsupport/clangcodemodelclientproxy.h @@ -57,6 +57,7 @@ public: void documentAnnotationsChanged(const DocumentAnnotationsChangedMessage &message) override; void references(const ReferencesMessage &message) override; void followSymbol(const FollowSymbolMessage &message) override; + void tooltip(const ToolTipMessage &message) override; void readMessages(); diff --git a/src/libs/clangsupport/clangcodemodelserverinterface.cpp b/src/libs/clangsupport/clangcodemodelserverinterface.cpp index bdaa802a47e..d50e97367d5 100644 --- a/src/libs/clangsupport/clangcodemodelserverinterface.cpp +++ b/src/libs/clangsupport/clangcodemodelserverinterface.cpp @@ -71,6 +71,9 @@ void ClangCodeModelServerInterface::dispatch(const MessageEnvelop &messageEnvelo case MessageType::RequestFollowSymbolMessage: requestFollowSymbol(messageEnvelop.message()); break; + case MessageType::RequestToolTipMessage: + requestToolTip(messageEnvelop.message()); + break; case MessageType::UpdateVisibleTranslationUnitsMessage: updateVisibleTranslationUnits(messageEnvelop.message()); break; diff --git a/src/libs/clangsupport/clangcodemodelserverinterface.h b/src/libs/clangsupport/clangcodemodelserverinterface.h index e4e897afc4d..eb24fa4dfed 100644 --- a/src/libs/clangsupport/clangcodemodelserverinterface.h +++ b/src/libs/clangsupport/clangcodemodelserverinterface.h @@ -50,6 +50,7 @@ public: virtual void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) = 0; virtual void requestReferences(const RequestReferencesMessage &message) = 0; virtual void requestFollowSymbol(const RequestFollowSymbolMessage &message) = 0; + virtual void requestToolTip(const RequestToolTipMessage &message) = 0; virtual void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) = 0; }; diff --git a/src/libs/clangsupport/clangcodemodelservermessages.h b/src/libs/clangsupport/clangcodemodelservermessages.h index b1ba7a07016..0e577b08ddd 100644 --- a/src/libs/clangsupport/clangcodemodelservermessages.h +++ b/src/libs/clangsupport/clangcodemodelservermessages.h @@ -36,6 +36,7 @@ #include "requestdocumentannotations.h" #include "requestreferencesmessage.h" #include "requestfollowsymbolmessage.h" +#include "requesttooltipmessage.h" #include "unregisterunsavedfilesforeditormessage.h" #include "updatetranslationunitsforeditormessage.h" #include "updatevisibletranslationunitsmessage.h" diff --git a/src/libs/clangsupport/clangcodemodelserverproxy.cpp b/src/libs/clangsupport/clangcodemodelserverproxy.cpp index f51bcb2802b..23a80284802 100644 --- a/src/libs/clangsupport/clangcodemodelserverproxy.cpp +++ b/src/libs/clangsupport/clangcodemodelserverproxy.cpp @@ -96,6 +96,11 @@ void ClangCodeModelServerProxy::requestFollowSymbol(const RequestFollowSymbolMes m_writeMessageBlock.write(message); } +void ClangCodeModelServerProxy::requestToolTip(const RequestToolTipMessage &message) +{ + m_writeMessageBlock.write(message); +} + void ClangCodeModelServerProxy::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) { m_writeMessageBlock.write(message); diff --git a/src/libs/clangsupport/clangcodemodelserverproxy.h b/src/libs/clangsupport/clangcodemodelserverproxy.h index e93e05d3f54..62ea90eebe2 100644 --- a/src/libs/clangsupport/clangcodemodelserverproxy.h +++ b/src/libs/clangsupport/clangcodemodelserverproxy.h @@ -60,6 +60,7 @@ public: void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override; void requestReferences(const RequestReferencesMessage &message) override; void requestFollowSymbol(const RequestFollowSymbolMessage &message) override; + void requestToolTip(const RequestToolTipMessage &message) override; void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override; }; diff --git a/src/libs/clangsupport/clangsupport-lib.pri b/src/libs/clangsupport/clangsupport-lib.pri index a32f78c1868..952fd72a10d 100644 --- a/src/libs/clangsupport/clangsupport-lib.pri +++ b/src/libs/clangsupport/clangsupport-lib.pri @@ -68,6 +68,7 @@ SOURCES += \ $$PWD/requestsourcelocationforrenamingmessage.cpp \ $$PWD/requestsourcerangesanddiagnosticsforquerymessage.cpp \ $$PWD/requestsourcerangesforquerymessage.cpp \ + $$PWD/requesttooltipmessage.cpp \ $$PWD/sourcelocationcontainer.cpp \ $$PWD/sourcelocationcontainerv2.cpp \ $$PWD/sourcelocationscontainer.cpp \ @@ -82,6 +83,8 @@ SOURCES += \ $$PWD/sourcerangesforquerymessage.cpp \ $$PWD/sourcerangewithtextcontainer.cpp \ $$PWD/tokeninfocontainer.cpp \ + $$PWD/tooltipmessage.cpp \ + $$PWD/tooltipinfo.cpp \ $$PWD/unregisterunsavedfilesforeditormessage.cpp \ $$PWD/updatepchprojectpartsmessage.cpp \ $$PWD/updatetranslationunitsforeditormessage.cpp \ @@ -159,6 +162,7 @@ HEADERS += \ $$PWD/requestsourcelocationforrenamingmessage.h \ $$PWD/requestsourcerangesanddiagnosticsforquerymessage.h \ $$PWD/requestsourcerangesforquerymessage.h \ + $$PWD/requesttooltipmessage.h \ $$PWD/sourcelocationcontainer.h \ $$PWD/sourcelocationcontainerv2.h \ $$PWD/sourcelocationscontainer.h \ @@ -176,6 +180,8 @@ HEADERS += \ $$PWD/sourcerangewithtextcontainer.h \ $$PWD/stringcache.h \ $$PWD/tokeninfocontainer.h \ + $$PWD/tooltipmessage.h \ + $$PWD/tooltipinfo.h \ $$PWD/unregisterunsavedfilesforeditormessage.h \ $$PWD/updatepchprojectpartsmessage.h \ $$PWD/updatetranslationunitsforeditormessage.h \ diff --git a/src/libs/clangsupport/clangsupport_global.h b/src/libs/clangsupport/clangsupport_global.h index 15c2679e2e3..1a368162e1e 100644 --- a/src/libs/clangsupport/clangsupport_global.h +++ b/src/libs/clangsupport/clangsupport_global.h @@ -120,6 +120,9 @@ enum class MessageType : quint8 { RequestFollowSymbolMessage, FollowSymbolMessage, + RequestToolTipMessage, + ToolTipMessage, + UpdateVisibleTranslationUnitsMessage, CompleteCodeMessage, diff --git a/src/libs/clangsupport/filecontainer.cpp b/src/libs/clangsupport/filecontainer.cpp index e2efc70b896..05f888aebf8 100644 --- a/src/libs/clangsupport/filecontainer.cpp +++ b/src/libs/clangsupport/filecontainer.cpp @@ -37,7 +37,8 @@ QDebug operator<<(QDebug debug, const FileContainer &container) << container.filePath() << ", " << container.projectPartId() << ", " << container.fileArguments() << ", " - << container.documentRevision(); + << container.documentRevision() << ", " + << container.textCodecName(); if (container.hasUnsavedFileContent()) { const Utf8String fileWithContent = debugWriteFileForInspection( diff --git a/src/libs/clangsupport/filecontainer.h b/src/libs/clangsupport/filecontainer.h index c7cb3f10053..b19c0daa46a 100644 --- a/src/libs/clangsupport/filecontainer.h +++ b/src/libs/clangsupport/filecontainer.h @@ -42,10 +42,12 @@ public: const Utf8String &projectPartId, const Utf8String &unsavedFileContent = Utf8String(), bool hasUnsavedFileContent = false, - quint32 documentRevision = 0) + quint32 documentRevision = 0, + const Utf8String &textCodecName = Utf8String()) : m_filePath(filePath), m_projectPartId(projectPartId), m_unsavedFileContent(unsavedFileContent), + m_textCodecName(textCodecName), m_documentRevision(documentRevision), m_hasUnsavedFileContent(hasUnsavedFileContent) { @@ -98,6 +100,11 @@ public: return m_unsavedFileContent; } + const Utf8String &textCodecName() const + { + return m_textCodecName; + } + bool hasUnsavedFileContent() const { return m_hasUnsavedFileContent; @@ -114,6 +121,7 @@ public: out << container.m_projectPartId; out << container.m_fileArguments; out << container.m_unsavedFileContent; + out << container.m_textCodecName; out << container.m_documentRevision; out << container.m_hasUnsavedFileContent; @@ -126,6 +134,7 @@ public: in >> container.m_projectPartId; in >> container.m_fileArguments; in >> container.m_unsavedFileContent; + in >> container.m_textCodecName; in >> container.m_documentRevision; in >> container.m_hasUnsavedFileContent; @@ -142,6 +151,7 @@ private: Utf8String m_projectPartId; Utf8StringVector m_fileArguments; Utf8String m_unsavedFileContent; + Utf8String m_textCodecName; quint32 m_documentRevision = 0; bool m_hasUnsavedFileContent = false; }; diff --git a/src/libs/clangsupport/messageenvelop.cpp b/src/libs/clangsupport/messageenvelop.cpp index 58139c4c8fd..134616a5b93 100644 --- a/src/libs/clangsupport/messageenvelop.cpp +++ b/src/libs/clangsupport/messageenvelop.cpp @@ -68,6 +68,9 @@ QDebug operator<<(QDebug debug, const MessageEnvelop &messageEnvelop) case MessageType::RequestReferencesMessage: qDebug() << messageEnvelop.message(); break; + case MessageType::RequestToolTipMessage: + qDebug() << messageEnvelop.message(); + break; case MessageType::UpdateVisibleTranslationUnitsMessage: qDebug() << messageEnvelop.message(); break; @@ -83,6 +86,9 @@ QDebug operator<<(QDebug debug, const MessageEnvelop &messageEnvelop) case MessageType::ReferencesMessage: qDebug() << messageEnvelop.message(); break; + case MessageType::ToolTipMessage: + qDebug() << messageEnvelop.message(); + break; case MessageType::DocumentAnnotationsChangedMessage: qDebug() << messageEnvelop.message(); break; diff --git a/src/libs/clangsupport/requesttooltipmessage.cpp b/src/libs/clangsupport/requesttooltipmessage.cpp new file mode 100644 index 00000000000..77ffdb46d80 --- /dev/null +++ b/src/libs/clangsupport/requesttooltipmessage.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "requesttooltipmessage.h" + +#include + +namespace ClangBackEnd { + +quint64 RequestToolTipMessage::ticketCounter = 0; + +QDebug operator<<(QDebug debug, const RequestToolTipMessage &message) +{ + debug.nospace() << "RequestToolTipMessage("; + + debug.nospace() << message.m_fileContainer << ", "; + debug.nospace() << message.m_ticketNumber << ", "; + debug.nospace() << message.m_line << ", "; + debug.nospace() << message.m_column << ", "; + + debug.nospace() << ")"; + + return debug; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/requesttooltipmessage.h b/src/libs/clangsupport/requesttooltipmessage.h new file mode 100644 index 00000000000..066d7358786 --- /dev/null +++ b/src/libs/clangsupport/requesttooltipmessage.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "clangsupport_global.h" + +#include "filecontainer.h" + +#include + +namespace ClangBackEnd { + +// TODO: De-duplicate with RequestReferencesMessage? +class RequestToolTipMessage +{ +public: + RequestToolTipMessage() = default; + RequestToolTipMessage(const FileContainer &fileContainer, quint32 line, quint32 column) + : m_fileContainer(fileContainer) + , m_ticketNumber(++ticketCounter) + , m_line(line) + , m_column(column) + { + } + + const FileContainer fileContainer() const { return m_fileContainer; } + quint32 line() const { return m_line; } + quint32 column() const { return m_column; } + quint64 ticketNumber() const { return m_ticketNumber; } + + friend QDataStream &operator<<(QDataStream &out, const RequestToolTipMessage &message) + { + out << message.m_fileContainer; + out << message.m_ticketNumber; + out << message.m_line; + out << message.m_column; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, RequestToolTipMessage &message) + { + in >> message.m_fileContainer; + in >> message.m_ticketNumber; + in >> message.m_line; + in >> message.m_column; + + return in; + } + + friend bool operator==(const RequestToolTipMessage &first, + const RequestToolTipMessage &second) + { + return first.m_ticketNumber == second.m_ticketNumber + && first.m_line == second.m_line + && first.m_column == second.m_column + && first.m_fileContainer == second.m_fileContainer; + } + + friend CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const RequestToolTipMessage &message); + +private: + FileContainer m_fileContainer; + quint64 m_ticketNumber = 0; + quint32 m_line = 0; + quint32 m_column = 0; + static CLANGSUPPORT_EXPORT quint64 ticketCounter; +}; + +DECLARE_MESSAGE(RequestToolTipMessage); +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/tooltipinfo.cpp b/src/libs/clangsupport/tooltipinfo.cpp new file mode 100644 index 00000000000..fc9a3394214 --- /dev/null +++ b/src/libs/clangsupport/tooltipinfo.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "tooltipinfo.h" + +#include + +namespace ClangBackEnd { + +#define RETURN_TEXT_FOR_CASE(enumValue) case ToolTipInfo::enumValue: return #enumValue +const char *qdocCategoryToString(ToolTipInfo::QdocCategory category) +{ + switch (category) { + RETURN_TEXT_FOR_CASE(Unknown); + RETURN_TEXT_FOR_CASE(ClassOrNamespace); + RETURN_TEXT_FOR_CASE(Enum); + RETURN_TEXT_FOR_CASE(Typedef); + RETURN_TEXT_FOR_CASE(Macro); + RETURN_TEXT_FOR_CASE(Brief); + RETURN_TEXT_FOR_CASE(Function); + } + + return "UnhandledQdocCategory"; +} +#undef RETURN_TEXT_FOR_CASE + +QDebug operator<<(QDebug debug, const ToolTipInfo &message) +{ + debug.nospace() << "ToolTipInfo("; + + debug.nospace() << message.m_text << ", "; + debug.nospace() << message.m_briefComment << ", "; + debug.nospace() << message.m_qdocIdCandidates << ", "; + debug.nospace() << message.m_qdocMark << ", "; + debug.nospace() << qdocCategoryToString(message.m_qdocCategory) << ", "; + debug.nospace() << message.m_sizeInBytes << ", "; + + debug.nospace() << ")"; + + return debug; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/tooltipinfo.h b/src/libs/clangsupport/tooltipinfo.h new file mode 100644 index 00000000000..b210d0dfe66 --- /dev/null +++ b/src/libs/clangsupport/tooltipinfo.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 +#include + +namespace ClangBackEnd { + +class ToolTipInfo +{ +public: + enum QdocCategory : quint8 { + Unknown, + ClassOrNamespace, + Enum, + Typedef, + Macro, + Brief, + Function, + }; + +public: + ToolTipInfo() = default; + ToolTipInfo(const Utf8String &text) : m_text(text) {} + + const Utf8String &text() const { return m_text; } + void setText(const Utf8String &text) { m_text = text; } + + const Utf8String &briefComment() const { return m_briefComment; } + void setBriefComment(const Utf8String &briefComment) { m_briefComment = briefComment; } + + const Utf8StringVector &qdocIdCandidates() const { return m_qdocIdCandidates; } + void setQdocIdCandidates(const Utf8StringVector &qdocIdCandidates) + { m_qdocIdCandidates = qdocIdCandidates; } + + const Utf8String &qdocMark() const { return m_qdocMark; } + void setQdocMark(const Utf8String &qdocMark) { m_qdocMark = qdocMark; } + + const QdocCategory &qdocCategory() const { return m_qdocCategory; } + void setQdocCategory(const QdocCategory &qdocCategory) { m_qdocCategory = qdocCategory; } + + const Utf8String &sizeInBytes() const { return m_sizeInBytes; } + void setSizeInBytes(const Utf8String &sizeInBytes) { m_sizeInBytes = sizeInBytes; } + + friend QDataStream &operator<<(QDataStream &out, const ToolTipInfo &message) + { + out << message.m_text; + out << message.m_briefComment; + out << message.m_qdocIdCandidates; + out << message.m_qdocMark; + out << static_cast(message.m_qdocCategory); + out << message.m_sizeInBytes; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, ToolTipInfo &message) + { + quint8 qdocCategory; + + in >> message.m_text; + in >> message.m_briefComment; + in >> message.m_qdocIdCandidates; + in >> message.m_qdocMark; + in >> qdocCategory; + in >> message.m_sizeInBytes; + + message.m_qdocCategory = static_cast(qdocCategory); + + return in; + } + + friend bool operator==(const ToolTipInfo &first, const ToolTipInfo &second) + { + return first.m_text == second.m_text + && first.m_briefComment == second.m_briefComment + && first.m_qdocIdCandidates == second.m_qdocIdCandidates + && first.m_qdocMark == second.m_qdocMark + && first.m_qdocCategory == second.m_qdocCategory + && first.m_sizeInBytes == second.m_sizeInBytes; + } + + friend QDebug operator<<(QDebug debug, const ToolTipInfo &message); + friend std::ostream &operator<<(std::ostream &os, const ToolTipInfo &message); + +private: + Utf8String m_text; + Utf8String m_briefComment; + + Utf8StringVector m_qdocIdCandidates; + Utf8String m_qdocMark; + QdocCategory m_qdocCategory = Unknown; + + // For class definition and for class fields. + Utf8String m_sizeInBytes; +}; + +const char *qdocCategoryToString(ToolTipInfo::QdocCategory category); + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/tooltipmessage.cpp b/src/libs/clangsupport/tooltipmessage.cpp new file mode 100644 index 00000000000..6e64fe33694 --- /dev/null +++ b/src/libs/clangsupport/tooltipmessage.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "tooltipmessage.h" + +#include + +namespace ClangBackEnd { + +QDebug operator<<(QDebug debug, const ToolTipMessage &message) +{ + debug.nospace() << "ToolTipMessage(" + << message.fileContainer() + << ", " << message.m_ticketNumber + << ", " << message.m_toolTipInfo; + + debug.nospace() << ")"; + + return debug; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/tooltipmessage.h b/src/libs/clangsupport/tooltipmessage.h new file mode 100644 index 00000000000..5d748179a66 --- /dev/null +++ b/src/libs/clangsupport/tooltipmessage.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "filecontainer.h" +#include "tooltipinfo.h" + +#include + +namespace ClangBackEnd { + +class ToolTipMessage +{ +public: + ToolTipMessage() = default; + ToolTipMessage(const FileContainer &fileContainer, + const ToolTipInfo &toolTipInfo, + quint64 ticketNumber) + : m_fileContainer(fileContainer) + , m_toolTipInfo(toolTipInfo) + , m_ticketNumber(ticketNumber) + { + } + + const FileContainer &fileContainer() const { return m_fileContainer; } + const ToolTipInfo &toolTipInfo() const { return m_toolTipInfo; } + quint64 ticketNumber() const { return m_ticketNumber; } + + friend QDataStream &operator<<(QDataStream &out, const ToolTipMessage &message) + { + out << message.m_fileContainer; + out << message.m_toolTipInfo;; + out << message.m_ticketNumber; + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, ToolTipMessage &message) + { + in >> message.m_fileContainer; + in >> message.m_toolTipInfo; + in >> message.m_ticketNumber; + + return in; + } + + friend bool operator==(const ToolTipMessage &first, const ToolTipMessage &second) + { + return first.m_ticketNumber == second.m_ticketNumber + && first.m_fileContainer == second.m_fileContainer + && first.m_toolTipInfo == second.m_toolTipInfo; + } + + friend CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const ToolTipMessage &message); + friend std::ostream &operator<<(std::ostream &os, const ToolTipMessage &message); + +private: + FileContainer m_fileContainer; + ToolTipInfo m_toolTipInfo; + quint64 m_ticketNumber = 0; +}; + +DECLARE_MESSAGE(ToolTipMessage) +} // namespace ClangBackEnd diff --git a/src/libs/sqlite/utf8string.h b/src/libs/sqlite/utf8string.h index 3c0f48519a2..5aa38956d15 100644 --- a/src/libs/sqlite/utf8string.h +++ b/src/libs/sqlite/utf8string.h @@ -171,7 +171,8 @@ public: byteArray.reserve(reserveSize); } - static Utf8String number(int number, int base=10) + template + static Utf8String number(T number, int base = 10) { return Utf8String::fromByteArray(QByteArray::number(number, base)); } diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp index 56504793122..1abd6982edf 100644 --- a/src/plugins/clangcodemodel/clangbackendcommunicator.cpp +++ b/src/plugins/clangcodemodel/clangbackendcommunicator.cpp @@ -392,6 +392,15 @@ QFuture BackendCommunicator::requestLocalReferences( return m_receiver.addExpectedReferencesMessage(message.ticketNumber(), textDocument); } +QFuture BackendCommunicator::requestToolTip( + const FileContainer &fileContainer, quint32 line, quint32 column) +{ + const RequestToolTipMessage message(fileContainer, line, column); + m_sender->requestToolTip(message); + + return m_receiver.addExpectedToolTipMessage(message.ticketNumber()); +} + QFuture BackendCommunicator::requestFollowSymbol( const FileContainer &curFileContainer, quint32 line, diff --git a/src/plugins/clangcodemodel/clangbackendcommunicator.h b/src/plugins/clangcodemodel/clangbackendcommunicator.h index bd7494a6c20..b3cb166a391 100644 --- a/src/plugins/clangcodemodel/clangbackendcommunicator.h +++ b/src/plugins/clangcodemodel/clangbackendcommunicator.h @@ -82,6 +82,9 @@ public: quint32 line, quint32 column, QTextDocument *textDocument); + QFuture requestToolTip(const FileContainer &fileContainer, + quint32 line, + quint32 column); QFuture requestFollowSymbol(const FileContainer &curFileContainer, quint32 line, quint32 column); diff --git a/src/plugins/clangcodemodel/clangbackendreceiver.cpp b/src/plugins/clangcodemodel/clangbackendreceiver.cpp index 8d5ec92d00d..f2606d74cc5 100644 --- a/src/plugins/clangcodemodel/clangbackendreceiver.cpp +++ b/src/plugins/clangcodemodel/clangbackendreceiver.cpp @@ -128,6 +128,18 @@ QFuture BackendReceiver::addExpectedRequestFollowSymbolMes return futureInterface.future(); } +QFuture BackendReceiver::addExpectedToolTipMessage(quint64 ticket) +{ + QTC_CHECK(!m_toolTipsTable.contains(ticket)); + + QFutureInterface futureInterface; + futureInterface.reportStarted(); + + m_toolTipsTable.insert(ticket, futureInterface); + + return futureInterface.future(); +} + bool BackendReceiver::isExpectingCodeCompletedMessage() const { return !m_assistProcessorsTable.isEmpty(); @@ -272,6 +284,72 @@ void BackendReceiver::references(const ReferencesMessage &message) futureInterface.reportFinished(); } +static TextEditor::HelpItem::Category toHelpItemCategory(ToolTipInfo::QdocCategory category) +{ + switch (category) { + case ToolTipInfo::Unknown: + return TextEditor::HelpItem::Unknown; + case ToolTipInfo::ClassOrNamespace: + return TextEditor::HelpItem::ClassOrNamespace; + case ToolTipInfo::Enum: + return TextEditor::HelpItem::Enum; + case ToolTipInfo::Typedef: + return TextEditor::HelpItem::Typedef; + case ToolTipInfo::Macro: + return TextEditor::HelpItem::Macro; + case ToolTipInfo::Brief: + return TextEditor::HelpItem::Brief; + case ToolTipInfo::Function: + return TextEditor::HelpItem::Function; + } + + return TextEditor::HelpItem::Unknown; +} + +static QStringList toStringList(const Utf8StringVector &utf8StringVector) +{ + QStringList list; + list.reserve(utf8StringVector.size()); + + for (const Utf8String &utf8String : utf8StringVector) + list << utf8String.toString(); + + return list; +} + +static CppTools::ToolTipInfo toToolTipInfo(const ToolTipMessage &message) +{ + CppTools::ToolTipInfo info; + + const ToolTipInfo backendInfo = message.toolTipInfo(); + + info.text = backendInfo.text(); + info.briefComment = backendInfo.briefComment(); + + info.qDocIdCandidates = toStringList(backendInfo.qdocIdCandidates()); + info.qDocMark = backendInfo.qdocMark(); + info.qDocCategory = toHelpItemCategory(backendInfo.qdocCategory()); + + info.sizeInBytes = backendInfo.sizeInBytes(); + + return info; +} + +void BackendReceiver::tooltip(const ToolTipMessage &message) +{ + qCDebugIpc() << "ToolTipMessage" << message.toolTipInfo().text(); + + const quint64 ticket = message.ticketNumber(); + QFutureInterface futureInterface = m_toolTipsTable.take(ticket); + QTC_CHECK(futureInterface != QFutureInterface()); + + if (futureInterface.isCanceled()) + return; // A new request was issued making this one outdated. + + futureInterface.reportResult(toToolTipInfo(message)); + futureInterface.reportFinished(); +} + void BackendReceiver::followSymbol(const ClangBackEnd::FollowSymbolMessage &message) { qCDebugIpc() << "FollowSymbolMessage with" diff --git a/src/plugins/clangcodemodel/clangbackendreceiver.h b/src/plugins/clangcodemodel/clangbackendreceiver.h index d7a966eae98..921150a52dc 100644 --- a/src/plugins/clangcodemodel/clangbackendreceiver.h +++ b/src/plugins/clangcodemodel/clangbackendreceiver.h @@ -27,6 +27,7 @@ #include #include +#include #include @@ -59,6 +60,7 @@ public: const CppTools::SemanticInfo::LocalUseMap &localUses = CppTools::SemanticInfo::LocalUseMap()); QFuture addExpectedRequestFollowSymbolMessage(quint64 ticket); + QFuture addExpectedToolTipMessage(quint64 ticket); bool isExpectingCodeCompletedMessage() const; void reset(); @@ -70,6 +72,7 @@ private: void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &message) override; void references(const ClangBackEnd::ReferencesMessage &message) override; + void tooltip(const ClangBackEnd::ToolTipMessage &message) override; void followSymbol(const ClangBackEnd::FollowSymbolMessage &message) override; private: @@ -89,7 +92,7 @@ private: CppTools::SemanticInfo::LocalUseMap localUses; }; QHash m_referencesTable; - + QHash> m_toolTipsTable; QHash> m_followTable; }; diff --git a/src/plugins/clangcodemodel/clangbackendsender.cpp b/src/plugins/clangcodemodel/clangbackendsender.cpp index 089377083fb..f6f8aea1cf8 100644 --- a/src/plugins/clangcodemodel/clangbackendsender.cpp +++ b/src/plugins/clangcodemodel/clangbackendsender.cpp @@ -120,6 +120,13 @@ void BackendSender::requestReferences(const RequestReferencesMessage &message) m_connection->serverProxy().requestReferences(message); } +void BackendSender::requestToolTip(const RequestToolTipMessage &message) +{ + QTC_CHECK(m_connection->isConnected()); + qCDebug(ipcLog) << ">>>" << message; + m_connection->serverProxy().requestToolTip(message); +} + void BackendSender::requestFollowSymbol(const RequestFollowSymbolMessage &message) { QTC_CHECK(m_connection->isConnected()); diff --git a/src/plugins/clangcodemodel/clangbackendsender.h b/src/plugins/clangcodemodel/clangbackendsender.h index ca9238ae651..f01326a4dc3 100644 --- a/src/plugins/clangcodemodel/clangbackendsender.h +++ b/src/plugins/clangcodemodel/clangbackendsender.h @@ -48,6 +48,7 @@ public: void completeCode(const ClangBackEnd::CompleteCodeMessage &message) override; void requestDocumentAnnotations(const ClangBackEnd::RequestDocumentAnnotationsMessage &message) override; void requestReferences(const ClangBackEnd::RequestReferencesMessage &message) override; + void requestToolTip(const ClangBackEnd::RequestToolTipMessage &message) override; void requestFollowSymbol(const ClangBackEnd::RequestFollowSymbolMessage &message) override; void updateVisibleTranslationUnits(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message) override; diff --git a/src/plugins/clangcodemodel/clangcodemodel.pro b/src/plugins/clangcodemodel/clangcodemodel.pro index 9136db5db5c..0e444a350e2 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.pro +++ b/src/plugins/clangcodemodel/clangcodemodel.pro @@ -30,6 +30,7 @@ SOURCES += \ clangfixitoperationsextractor.cpp \ clangfollowsymbol.cpp \ clangfunctionhintmodel.cpp \ + clanghoverhandler.cpp \ clangtokeninfosreporter.cpp \ clangmodelmanagersupport.cpp \ clangpreprocessorassistproposalitem.cpp \ @@ -66,6 +67,7 @@ HEADERS += \ clangfixitoperationsextractor.h \ clangfollowsymbol.h \ clangfunctionhintmodel.h \ + clanghoverhandler.h \ clangisdiagnosticrelatedtolocation.h \ clangmodelmanagersupport.h \ clangpreprocessorassistproposalitem.h \ diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index cc81025925f..90105b86d38 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -80,6 +80,8 @@ QtcPlugin { "clangfollowsymbol.h", "clangfunctionhintmodel.cpp", "clangfunctionhintmodel.h", + "clanghoverhandler.cpp", + "clanghoverhandler.h", "clangtokeninfosreporter.cpp", "clangtokeninfosreporter.h", "clangisdiagnosticrelatedtolocation.h", diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 6eb98b2c92f..a282350f246 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -375,6 +375,15 @@ ClangEditorDocumentProcessor::requestFollowSymbol(int line, int column) static_cast(column)); } +QFuture ClangEditorDocumentProcessor::toolTipInfo(const QByteArray &codecName, + int line, + int column) +{ + return m_communicator.requestToolTip(simpleFileContainer(codecName), + static_cast(line), + static_cast(column)); +} + ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithArguments() const { return fileContainerWithArguments(m_projectPart.data()); @@ -480,13 +489,19 @@ ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget( }; } -ClangBackEnd::FileContainer ClangEditorDocumentProcessor::simpleFileContainer() const +ClangBackEnd::FileContainer ClangEditorDocumentProcessor::simpleFileContainer( + const QByteArray &codecName) const { Utf8String projectPartId; if (m_projectPart) projectPartId = m_projectPart->id(); - return ClangBackEnd::FileContainer(filePath(), projectPartId, Utf8String(), false, revision()); + return ClangBackEnd::FileContainer(filePath(), + projectPartId, + Utf8String(), + false, + revision(), + Utf8String::fromByteArray(codecName)); } static CppTools::ProjectPart projectPartForLanguageOption(CppTools::ProjectPart *projectPart) diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h index 2bb7ca04633..67745b582cb 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h @@ -88,6 +88,9 @@ public: QFuture cursorInfo(const CppTools::CursorInfoParams ¶ms) override; QFuture requestLocalReferences(const QTextCursor &cursor) override; QFuture requestFollowSymbol(int line, int column) override; + QFuture toolTipInfo(const QByteArray &codecName, + int line, + int column) override; ClangBackEnd::FileContainer fileContainerWithArguments() const; @@ -106,7 +109,7 @@ private: void requestDocumentAnnotations(const QString &projectpartId); HeaderErrorDiagnosticWidgetCreator creatorForHeaderErrorDiagnosticWidget( const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic); - ClangBackEnd::FileContainer simpleFileContainer() const; + ClangBackEnd::FileContainer simpleFileContainer(const QByteArray &codecName = QByteArray()) const; ClangBackEnd::FileContainer fileContainerWithArguments(CppTools::ProjectPart *projectPart) const; ClangBackEnd::FileContainer fileContainerWithArgumentsAndDocumentContent( CppTools::ProjectPart *projectPart) const; diff --git a/src/plugins/clangcodemodel/clanghoverhandler.cpp b/src/plugins/clangcodemodel/clanghoverhandler.cpp new file mode 100644 index 00000000000..6610b555c22 --- /dev/null +++ b/src/plugins/clangcodemodel/clanghoverhandler.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "clanghoverhandler.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(hoverLog, "qtc.clangcodemodel.hover"); + +using namespace TextEditor; + +namespace ClangCodeModel { +namespace Internal { + +static CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor(TextEditorWidget *editorWidget) +{ + const QString filePath = editorWidget->textDocument()->filePath().toString(); + auto cppModelManager = CppTools::CppModelManager::instance(); + CppTools::CppEditorDocumentHandle *editorHandle = cppModelManager->cppEditorDocument(filePath); + + if (editorHandle) + return editorHandle->processor(); + + return 0; +} + +static bool editorDocumentProcessorHasDiagnosticAt(TextEditorWidget *editorWidget, int pos) +{ + if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { + int line, column; + if (Utils::Text::convertPosition(editorWidget->document(), pos, &line, &column)) + return processor->hasDiagnosticsAt(line, column); + } + + return false; +} + +static void processWithEditorDocumentProcessor(TextEditorWidget *editorWidget, + const QPoint &point, + int position, + const QString &helpId) +{ + if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { + int line, column; + if (Utils::Text::convertPosition(editorWidget->document(), position, &line, &column)) { + auto layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(2); + processor->addDiagnosticToolTipToLayout(line, column, layout); + Utils::ToolTip::show(point, layout, editorWidget, helpId); + } + } +} + +static QFuture editorDocumentHandlesToolTipInfo( + TextEditorWidget *editorWidget, int pos) +{ + const QByteArray textCodecName = editorWidget->textDocument()->codec()->name(); + if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { + int line, column; + if (Utils::Text::convertPosition(editorWidget->document(), pos, &line, &column)) + return processor->toolTipInfo(textCodecName, line, column + 1); + } + + return QFuture(); +} + +ClangHoverHandler::ClangHoverHandler() +{ + setIsAsyncHandler(true); +} + +ClangHoverHandler::~ClangHoverHandler() +{ + cancelAsyncCheck(); +} + +void ClangHoverHandler::identifyMatchAsync(TextEditorWidget *editorWidget, + int pos, + BaseHoverHandler::ReportPriority report) +{ + // Reset + m_futureWatcher.reset(); + m_cursorPosition = -1; + + // Check for diagnostics (sync) + if (editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) { + qCDebug(hoverLog) << "Checking for diagnostic at" << pos; + setPriority(Priority_Diagnostic); + m_cursorPosition = pos; + report(priority()); + return; + } + + // Check for tooltips (async) + QFuture future = editorDocumentHandlesToolTipInfo(editorWidget, pos); + if (QTC_GUARD(future.isRunning())) { + qCDebug(hoverLog) << "Requesting tooltip info at" << pos; + m_reportPriority = report; + m_futureWatcher.reset(new QFutureWatcher()); + QObject::connect(m_futureWatcher.data(), &QFutureWatcherBase::finished, [this]() { + processToolTipInfo(m_futureWatcher->result()); + }); + m_futureWatcher->setFuture(future); + return; + } + + report(Priority_None); // Ops, something went wrong. +} + +void ClangHoverHandler::cancelAsyncCheck() +{ + if (m_futureWatcher) + m_futureWatcher->cancel(); +} + +#define RETURN_TEXT_FOR_CASE(enumValue) case TextEditor::HelpItem::enumValue: return #enumValue +static const char *helpItemCategoryAsString(TextEditor::HelpItem::Category category) +{ + switch (category) { + RETURN_TEXT_FOR_CASE(Unknown); + RETURN_TEXT_FOR_CASE(ClassOrNamespace); + RETURN_TEXT_FOR_CASE(Enum); + RETURN_TEXT_FOR_CASE(Typedef); + RETURN_TEXT_FOR_CASE(Macro); + RETURN_TEXT_FOR_CASE(Brief); + RETURN_TEXT_FOR_CASE(Function); + RETURN_TEXT_FOR_CASE(QmlComponent); + RETURN_TEXT_FOR_CASE(QmlProperty); + RETURN_TEXT_FOR_CASE(QMakeVariableOfFunction); + } + + return "UnhandledHelpItemCategory"; +} +#undef RETURN_TEXT_FOR_CASE + +void ClangHoverHandler::processToolTipInfo(const CppTools::ToolTipInfo &info) +{ + qCDebug(hoverLog) << "Processing tooltip info" << info.text; + + QString text = info.text; + if (!info.briefComment.isEmpty()) + text.append("\n\n" + info.briefComment); + + for (const QString &qdocIdCandidate : info.qDocIdCandidates) { + qCDebug(hoverLog) << "Querying help manager with" + << qdocIdCandidate + << info.qDocMark + << helpItemCategoryAsString(info.qDocCategory); + const QMap helpLinks = Core::HelpManager::linksForIdentifier(qdocIdCandidate); + if (!helpLinks.isEmpty()) { + qCDebug(hoverLog) << " Match!"; + setLastHelpItemIdentified( + HelpItem(qdocIdCandidate, info.qDocMark, info.qDocCategory, helpLinks)); + break; + } + } + + if (!info.sizeInBytes.isEmpty()) + text.append(tr("\n\n%1 bytes").arg(info.sizeInBytes)); + + setToolTip(text); + m_reportPriority(priority()); +} + +void ClangHoverHandler::decorateToolTip() +{ + if (priority() == Priority_Diagnostic) + return; + + if (Qt::mightBeRichText(toolTip())) + setToolTip(toolTip().toHtmlEscaped()); + + const HelpItem &help = lastHelpItemIdentified(); + if (help.isValid()) { + const QString text = CppTools::CppHoverHandler::tooltipTextForHelpItem(help); + if (!text.isEmpty()) + setToolTip(text); + } +} + +void ClangHoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidget, + const QPoint &point) +{ + if (priority() == Priority_Diagnostic) { + const HelpItem helpItem = lastHelpItemIdentified(); + const QString helpId = helpItem.isValid() ? helpItem.helpId() : QString(); + processWithEditorDocumentProcessor(editorWidget, point, m_cursorPosition, helpId); + return; + } + + // Priority_Tooltip / Priority_Help + BaseHoverHandler::operateTooltip(editorWidget, point); +} + +} // namespace Internal +} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clanghoverhandler.h b/src/plugins/clangcodemodel/clanghoverhandler.h new file mode 100644 index 00000000000..85b7999f94b --- /dev/null +++ b/src/plugins/clangcodemodel/clanghoverhandler.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 +#include +#include + +namespace ClangCodeModel { +namespace Internal { + +class ClangHoverHandler : public TextEditor::BaseHoverHandler +{ + Q_DECLARE_TR_FUNCTIONS(ClangHoverHandler) + +public: + ClangHoverHandler(); + ~ClangHoverHandler() override; + + void identifyMatchAsync(TextEditor::TextEditorWidget *editorWidget, + int pos, + ReportPriority report) override; + void decorateToolTip() override; + void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override; + +private: + void cancelAsyncCheck() override; + void processToolTipInfo(const CppTools::ToolTipInfo &info); + +private: + int m_cursorPosition = -1; + QScopedPointer> m_futureWatcher; + ReportPriority m_reportPriority; +}; + +} // namespace Internal +} // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 9271975dfde..9495e6d5ebc 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -29,11 +29,11 @@ #include "clangeditordocumentprocessor.h" #include "clangutils.h" #include "clangfollowsymbol.h" +#include "clanghoverhandler.h" #include "clangrefactoringengine.h" #include #include -#include #include #include #include @@ -114,7 +114,7 @@ CppTools::CppCompletionAssistProvider *ModelManagerSupportClang::completionAssis TextEditor::BaseHoverHandler *ModelManagerSupportClang::createHoverHandler() { - return new CppTools::CppHoverHandler; + return new Internal::ClangHoverHandler; } CppTools::FollowSymbolInterface &ModelManagerSupportClang::followSymbolInterface() diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.cpp b/src/plugins/cpptools/baseeditordocumentprocessor.cpp index 5bffb51a382..20632289c68 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.cpp +++ b/src/plugins/cpptools/baseeditordocumentprocessor.cpp @@ -97,6 +97,13 @@ void BaseEditorDocumentProcessor::setParserConfig( parser()->setConfiguration(config); } +QFuture BaseEditorDocumentProcessor::toolTipInfo(const QByteArray &/*codecName*/, + int /*line*/, + int /*column*/) +{ + return QFuture(); +} + void BaseEditorDocumentProcessor::runParser(QFutureInterface &future, BaseEditorDocumentParser::Ptr parser, BaseEditorDocumentParser::UpdateParams updateParams) diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.h b/src/plugins/cpptools/baseeditordocumentprocessor.h index b3f96d466de..d799c636b25 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.h +++ b/src/plugins/cpptools/baseeditordocumentprocessor.h @@ -32,6 +32,7 @@ #include "cpptools_global.h" #include +#include #include #include #include @@ -48,6 +49,18 @@ class TextDocument; namespace CppTools { +// For clang code model only, move? +struct CPPTOOLS_EXPORT ToolTipInfo { + QString text; + QString briefComment; + + QStringList qDocIdCandidates; + QString qDocMark; + TextEditor::HelpItem::Category qDocCategory; + + QString sizeInBytes; +}; + class CPPTOOLS_EXPORT BaseEditorDocumentProcessor : public QObject { Q_OBJECT @@ -78,6 +91,7 @@ public: virtual QFuture cursorInfo(const CursorInfoParams ¶ms) = 0; virtual QFuture requestLocalReferences(const QTextCursor &cursor) = 0; virtual QFuture requestFollowSymbol(int line, int column) = 0; + virtual QFuture toolTipInfo(const QByteArray &codecName, int line, int column); public: using HeaderErrorDiagnosticWidgetCreator = std::function; diff --git a/src/plugins/cpptools/cpphoverhandler.cpp b/src/plugins/cpptools/cpphoverhandler.cpp index 9b9a8edff74..1ff41b7fdc3 100644 --- a/src/plugins/cpptools/cpphoverhandler.cpp +++ b/src/plugins/cpptools/cpphoverhandler.cpp @@ -28,78 +28,47 @@ #include "cppelementevaluator.h" #include -#include -#include -#include #include #include -#include -#include #include #include -#include using namespace Core; using namespace TextEditor; -namespace { - -CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor(TextEditorWidget *editorWidget) -{ - const QString filePath = editorWidget->textDocument()->filePath().toString(); - auto cppModelManager = CppTools::CppModelManager::instance(); - CppTools::CppEditorDocumentHandle *editorHandle = cppModelManager->cppEditorDocument(filePath); - - if (editorHandle) - return editorHandle->processor(); - - return 0; -} - -bool editorDocumentProcessorHasDiagnosticAt(TextEditorWidget *editorWidget, int pos) -{ - if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { - int line, column; - if (Utils::Text::convertPosition(editorWidget->document(), pos, &line, &column)) - return processor->hasDiagnosticsAt(line, column); - } - - return false; -} - -void processWithEditorDocumentProcessor(TextEditorWidget *editorWidget, - const QPoint &point, - int position, - const QString &helpId) -{ - if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { - int line, column; - if (Utils::Text::convertPosition(editorWidget->document(), position, &line, &column)) { - auto layout = new QVBoxLayout; - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(2); - processor->addDiagnosticToolTipToLayout(line, column, layout); - Utils::ToolTip::show(point, layout, editorWidget, helpId); - } - } -} - -} // anonymous namespace - namespace CppTools { +QString CppHoverHandler::tooltipTextForHelpItem(const HelpItem &helpItem) +{ + // If Qt is built with a namespace, we still show the tip without it, as + // it is in the docs and for consistency with the doc extraction mechanism. + const HelpItem::Category category = helpItem.category(); + const QString &contents = helpItem.extractContent(false); + if (!contents.isEmpty()) { + if (category == HelpItem::ClassOrNamespace) + return helpItem.helpId() + contents; + else + return contents; + } else if (category == HelpItem::Typedef || + category == HelpItem::Enum || + category == HelpItem::ClassOrNamespace) { + // This approach is a bit limited since it cannot be used for functions + // because the help id doesn't really help in that case. + QString prefix; + if (category == HelpItem::Typedef) + prefix = QLatin1String("typedef "); + else if (category == HelpItem::Enum) + prefix = QLatin1String("enum "); + return prefix + helpItem.helpId(); + } + + return QString(); +} + void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos) { - m_positionForEditorDocumentProcessor = -1; - - if (editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) { - setPriority(Priority_Diagnostic); - m_positionForEditorDocumentProcessor = pos; - return; - } - QTextCursor tc(editorWidget->document()); tc.setPosition(pos); @@ -135,9 +104,6 @@ void CppHoverHandler::identifyMatch(TextEditorWidget *editorWidget, int pos) void CppHoverHandler::decorateToolTip() { - if (m_positionForEditorDocumentProcessor != -1) - return; - if (Qt::mightBeRichText(toolTip())) setToolTip(toolTip().toHtmlEscaped()); @@ -146,42 +112,10 @@ void CppHoverHandler::decorateToolTip() const HelpItem &help = lastHelpItemIdentified(); if (help.isValid()) { - // If Qt is built with a namespace, we still show the tip without it, as - // it is in the docs and for consistency with the doc extraction mechanism. - const HelpItem::Category category = help.category(); - const QString &contents = help.extractContent(false); - if (!contents.isEmpty()) { - if (category == HelpItem::ClassOrNamespace) - setToolTip(help.helpId() + contents); - else - setToolTip(contents); - } else if (category == HelpItem::Typedef || - category == HelpItem::Enum || - category == HelpItem::ClassOrNamespace) { - // This approach is a bit limited since it cannot be used for functions - // because the help id doesn't really help in that case. - QString prefix; - if (category == HelpItem::Typedef) - prefix = QLatin1String("typedef "); - else if (category == HelpItem::Enum) - prefix = QLatin1String("enum "); - setToolTip(prefix + help.helpId()); - } + const QString text = tooltipTextForHelpItem(help); + if (!text.isEmpty()) + setToolTip(text); } } -void CppHoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidget, - const QPoint &point) -{ - if (m_positionForEditorDocumentProcessor == -1) { - BaseHoverHandler::operateTooltip(editorWidget, point); - return; - } - - const HelpItem helpItem = lastHelpItemIdentified(); - const QString helpId = helpItem.isValid() ? helpItem.helpId() : QString(); - processWithEditorDocumentProcessor(editorWidget, point, m_positionForEditorDocumentProcessor, - helpId); -} - } // namespace CppTools diff --git a/src/plugins/cpptools/cpphoverhandler.h b/src/plugins/cpptools/cpphoverhandler.h index b728b970fe4..edfa6901cf8 100644 --- a/src/plugins/cpptools/cpphoverhandler.h +++ b/src/plugins/cpptools/cpphoverhandler.h @@ -33,13 +33,12 @@ namespace CppTools { class CPPTOOLS_EXPORT CppHoverHandler : public TextEditor::BaseHoverHandler { +public: + static QString tooltipTextForHelpItem(const TextEditor::HelpItem &help); + private: void identifyMatch(TextEditor::TextEditorWidget *editorWidget, int pos) override; void decorateToolTip() override; - void operateTooltip(TextEditor::TextEditorWidget *editorWidget, const QPoint &point) override; - -private: - int m_positionForEditorDocumentProcessor = -1; }; } // namespace CppTools diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index c3fb788d25b..4b2b428f019 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -309,6 +309,7 @@ public: const int documentRevision = textCursor.document()->revision(); const int position = Text::wordStartCursor(textCursor).position(); if (m_lastHandlerInfo.applies(documentRevision, position)) { + qDebug() << "Last handler applies, showing it"; m_lastHandlerInfo.handler->showToolTip(m_widget, point, /*decorate=*/ false); return; } @@ -364,6 +365,7 @@ public: // All were queried, run the best if (m_bestHandler) { + qDebug() << "setting last handler info:" << m_documentRevision << m_position; m_lastHandlerInfo = LastHandlerInfo(m_bestHandler, m_documentRevision, m_position); m_bestHandler->showToolTip(m_widget, m_point); } diff --git a/src/tools/clangbackend/source/clangbackend_global.h b/src/tools/clangbackend/source/clangbackend_global.h index e62c9a35130..a7ca7859587 100644 --- a/src/tools/clangbackend/source/clangbackend_global.h +++ b/src/tools/clangbackend/source/clangbackend_global.h @@ -36,4 +36,9 @@ enum class PreferredTranslationUnit LastUninitialized, }; +// CLANG-UPGRADE-CHECK: Remove IS_SUSPEND_SUPPORTED once we require clang >= 7.0 +#if defined(CINDEX_VERSION_HAS_PRETTYDECL_BACKPORTED) || CINDEX_VERSION_MINOR >= 47 +# define IS_PRETTY_DECL_SUPPORTED +#endif + } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/source/clangbackendclangipc-source.pri b/src/tools/clangbackend/source/clangbackendclangipc-source.pri index 3460e9d297d..154b5cc0194 100644 --- a/src/tools/clangbackend/source/clangbackendclangipc-source.pri +++ b/src/tools/clangbackend/source/clangbackendclangipc-source.pri @@ -29,10 +29,12 @@ HEADERS += \ $$PWD/clangreparsesupportivetranslationunitjob.h \ $$PWD/clangrequestdocumentannotationsjob.h \ $$PWD/clangrequestreferencesjob.h \ + $$PWD/clangrequesttooltipjob.h \ $$PWD/clangresumedocumentjob.h \ $$PWD/clangstring.h \ $$PWD/clangsupportivetranslationunitinitializer.h \ $$PWD/clangsuspenddocumentjob.h \ + $$PWD/clangtooltipinfocollector.h \ $$PWD/clangtranslationunit.h \ $$PWD/clangtranslationunits.h \ $$PWD/clangtranslationunitupdater.h \ @@ -86,8 +88,10 @@ SOURCES += \ $$PWD/clangreparsesupportivetranslationunitjob.cpp \ $$PWD/clangrequestdocumentannotationsjob.cpp \ $$PWD/clangrequestreferencesjob.cpp \ + $$PWD/clangrequesttooltipjob.cpp \ $$PWD/clangsuspenddocumentjob.cpp \ $$PWD/clangsupportivetranslationunitinitializer.cpp \ + $$PWD/clangtooltipinfocollector.cpp \ $$PWD/clangtranslationunit.cpp \ $$PWD/clangtranslationunits.cpp \ $$PWD/clangtranslationunitupdater.cpp \ diff --git a/src/tools/clangbackend/source/clangcodemodelserver.cpp b/src/tools/clangbackend/source/clangcodemodelserver.cpp index 6e3a4290b80..609ac1da85c 100644 --- a/src/tools/clangbackend/source/clangcodemodelserver.cpp +++ b/src/tools/clangbackend/source/clangcodemodelserver.cpp @@ -258,6 +258,7 @@ static void fillJobRequest(JobRequest &jobRequest, const MessageType &message) jobRequest.line = message.line(); jobRequest.column = message.column(); jobRequest.ticketNumber = message.ticketNumber(); + jobRequest.textCodecName = message.fileContainer().textCodecName(); // The unsaved files might get updater later, so take the current // revision for the request. jobRequest.documentRevision = message.fileContainer().documentRevision(); @@ -303,6 +304,25 @@ void ClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMessage } } +void ClangCodeModelServer::requestToolTip(const RequestToolTipMessage &message) +{ + TIME_SCOPE_DURATION("ClangCodeModelServer::requestToolTip"); + + try { + const Document document = documents.document(message.fileContainer().filePath(), + message.fileContainer().projectPartId()); + DocumentProcessor processor = documentProcessors().processor(document); + + JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::RequestToolTip); + fillJobRequest(jobRequest, message); + + processor.addJob(jobRequest); + processor.process(); + } catch (const std::exception &exception) { + qWarning() << "Error in ClangCodeModelServer::requestToolTip:" << exception.what(); + } +} + void ClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) { qCDebug(serverLog) << "########## updateVisibleTranslationUnits"; diff --git a/src/tools/clangbackend/source/clangcodemodelserver.h b/src/tools/clangbackend/source/clangcodemodelserver.h index 1591d25743c..98508f348c5 100644 --- a/src/tools/clangbackend/source/clangcodemodelserver.h +++ b/src/tools/clangbackend/source/clangcodemodelserver.h @@ -61,6 +61,7 @@ public: void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override; void requestReferences(const RequestReferencesMessage &message) override; void requestFollowSymbol(const RequestFollowSymbolMessage &message) override; + void requestToolTip(const RequestToolTipMessage &message) override; public: // for tests const Documents &documentsForTestOnly() const; diff --git a/src/tools/clangbackend/source/clangjobrequest.cpp b/src/tools/clangbackend/source/clangjobrequest.cpp index b40ea424257..e2c6f8f6d49 100644 --- a/src/tools/clangbackend/source/clangjobrequest.cpp +++ b/src/tools/clangbackend/source/clangjobrequest.cpp @@ -32,6 +32,7 @@ #include "clangreparsesupportivetranslationunitjob.h" #include "clangrequestdocumentannotationsjob.h" #include "clangrequestreferencesjob.h" +#include "clangrequesttooltipjob.h" #include "clangresumedocumentjob.h" #include "clangsuspenddocumentjob.h" #include "clangupdatedocumentannotationsjob.h" @@ -40,6 +41,7 @@ #include #include #include +#include #include @@ -62,6 +64,7 @@ static const char *JobRequestTypeToText(JobRequest::Type type) RETURN_TEXT_FOR_CASE(RequestDocumentAnnotations); RETURN_TEXT_FOR_CASE(RequestReferences); RETURN_TEXT_FOR_CASE(FollowSymbol); + RETURN_TEXT_FOR_CASE(RequestToolTip); RETURN_TEXT_FOR_CASE(SuspendDocument); RETURN_TEXT_FOR_CASE(ResumeDocument); } @@ -126,6 +129,7 @@ static JobRequest::ExpirationConditions expirationConditionsForType(JobRequest:: return Conditions(Condition::AnythingChanged); case Type::RequestReferences: case Type::RequestDocumentAnnotations: + case Type::RequestToolTip: case Type::FollowSymbol: return Conditions(Condition::DocumentClosed) | Conditions(Condition::DocumentRevisionChanged); @@ -153,8 +157,10 @@ static JobRequest::RunConditions conditionsForType(JobRequest::Type type) Conditions conditions = Conditions(Condition::DocumentUnsuspended) | Conditions(Condition::DocumentVisible); - if (type == Type::RequestReferences || type == Type::FollowSymbol) + if (type == Type::RequestReferences || type == Type::FollowSymbol + || type == Type::RequestToolTip) { conditions |= Condition::CurrentDocumentRevision; + } if (type != Type::UpdateDocumentAnnotations && type != Type::ParseSupportiveTranslationUnit) conditions |= Condition::DocumentParsed; @@ -192,6 +198,8 @@ IAsyncJob *JobRequest::createJob() const return new RequestDocumentAnnotationsJob(); case JobRequest::Type::RequestReferences: return new RequestReferencesJob(); + case JobRequest::Type::RequestToolTip: + return new RequestToolTipJob(); case JobRequest::Type::FollowSymbol: return new FollowSymbolJob(); case JobRequest::Type::SuspendDocument: @@ -224,6 +232,11 @@ void JobRequest::cancelJob(ClangCodeModelClientInterface &client) const false, ticketNumber)); break; + case JobRequest::Type::RequestToolTip: + client.tooltip(ToolTipMessage(FileContainer(), + ToolTipInfo(), + ticketNumber)); + break; case JobRequest::Type::CompleteCode: client.codeCompleted(CodeCompletedMessage(CodeCompletions(), CompletionCorrection::NoCorrection, diff --git a/src/tools/clangbackend/source/clangjobrequest.h b/src/tools/clangbackend/source/clangjobrequest.h index 4b79f22792e..81c78ba9dbc 100644 --- a/src/tools/clangbackend/source/clangjobrequest.h +++ b/src/tools/clangbackend/source/clangjobrequest.h @@ -59,6 +59,7 @@ public: RequestDocumentAnnotations, RequestReferences, FollowSymbol, + RequestToolTip, SuspendDocument, ResumeDocument, @@ -118,6 +119,7 @@ public: qint32 funcNameStartLine = -1; qint32 funcNameStartColumn = -1; quint64 ticketNumber = 0; + Utf8String textCodecName; bool localReferences = false; }; diff --git a/src/tools/clangbackend/source/clangrequesttooltipjob.cpp b/src/tools/clangbackend/source/clangrequesttooltipjob.cpp new file mode 100644 index 00000000000..0e1249e4e8b --- /dev/null +++ b/src/tools/clangbackend/source/clangrequesttooltipjob.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "clangrequesttooltipjob.h" + +#include +#include +#include + +#include + +namespace ClangBackEnd { + +IAsyncJob::AsyncPrepareResult RequestToolTipJob::prepareAsyncRun() +{ + const JobRequest jobRequest = context().jobRequest; + QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestToolTip, return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); + + const TranslationUnit translationUnit = *m_translationUnit; + const UnsavedFiles unsavedFiles = *context().unsavedFiles; + const quint32 line = jobRequest.line; + const quint32 column = jobRequest.column; + const Utf8String textCodecName = jobRequest.textCodecName; + setRunner([translationUnit, unsavedFiles, line, column, textCodecName]() { + TIME_SCOPE_DURATION("RequestToolTipJobRunner"); + + UnsavedFiles theUnsavedFiles = unsavedFiles; + return translationUnit.tooltip(theUnsavedFiles, textCodecName, line, column); + }); + return AsyncPrepareResult{translationUnit.id()}; +} + +void RequestToolTipJob::finalizeAsyncRun() +{ + if (!context().isOutdated()) { + const AsyncResult result = asyncResult(); + + context().client->tooltip(ToolTipMessage(m_pinnedFileContainer, + result, + context().jobRequest.ticketNumber)); + } +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangbackend/source/clangrequesttooltipjob.h b/src/tools/clangbackend/source/clangrequesttooltipjob.h new file mode 100644 index 00000000000..eb121402cb2 --- /dev/null +++ b/src/tools/clangbackend/source/clangrequesttooltipjob.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 + +#include "clangdocumentjob.h" + +namespace ClangBackEnd { + +class RequestToolTipJob : public DocumentJob +{ +public: + using AsyncResult = ToolTipInfo; + + AsyncPrepareResult prepareAsyncRun() override; + void finalizeAsyncRun() override; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangbackend/source/clangtooltipinfocollector.cpp b/src/tools/clangbackend/source/clangtooltipinfocollector.cpp new file mode 100644 index 00000000000..44dde1edbbc --- /dev/null +++ b/src/tools/clangbackend/source/clangtooltipinfocollector.cpp @@ -0,0 +1,531 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "clangtooltipinfocollector.h" + +#include "clangbackend_global.h" +#include "clangstring.h" +#include "cursor.h" +#include "sourcerange.h" +#include "unsavedfiles.h" +#include "unsavedfile.h" + +#include +#include +#include + +#include + +#include +#include +#include + +namespace ClangBackEnd { + +namespace { + +Utf8StringVector qualificationPrefixAsVector(const Cursor &cursor) +{ + Utf8StringVector result; + + for (Cursor parent = cursor.semanticParent(); + parent.isValid() && (parent.kind() == CXCursor_Namespace || parent.isCompoundType()); + parent = parent.semanticParent()) { + result.prepend(parent.spelling()); + } + + return result; +} + +Utf8String qualificationPrefix(const Cursor &cursor) +{ + // TODO: Implement with qualificationPrefixAsVector() + Utf8String qualifiedName; + + for (Cursor parent = cursor.semanticParent(); + parent.isValid() && (parent.kind() == CXCursor_Namespace); + parent = parent.semanticParent()) { + qualifiedName = parent.spelling() + Utf8StringLiteral("::") + qualifiedName; + } + + return qualifiedName; +} + +Utf8String displayName(const Cursor &cursor) +{ + if (cursor.kind() == CXCursor_ClassTemplate) { + // TODO: The qualification should be part of the display name. Fix this in libclang. + return qualificationPrefix(cursor) + cursor.displayName(); + } + + return cursor.displayName(); +} + +Utf8String textForFunctionLike(const Cursor &cursor) +{ +#ifdef IS_PRETTY_DECL_SUPPORTED + CXPrintingPolicy policy = clang_getCursorPrintingPolicy(cursor.cx()); + clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_FullyQualifiedName, 1); + clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_TerseOutput, 1); + // Avoid printing attributes/pragmas + clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_PolishForDeclaration, 1); + clang_PrintingPolicy_setProperty(policy, CXPrintingPolicy_SuppressInitializers, 1); + const Utf8String prettyPrinted = ClangString( + clang_getCursorPrettyPrinted(cursor.cx(), policy)); + clang_PrintingPolicy_dispose(policy); + return prettyPrinted; +#else + // Printing function declarations with displayName() is quite limited: + // * result type is not included + // * parameter names are not included + // * templates in the result type are not included + // * no full qualification of the function name + return Utf8String(cursor.resultType().spelling()) + + Utf8StringLiteral(" ") + + qualificationPrefix(cursor) + + Utf8String(cursor.displayName()); +#endif +} + +Utf8String textForEnumConstantDecl(const Cursor &cursor) +{ + const Cursor semanticParent = cursor.semanticParent(); + QTC_ASSERT(semanticParent.kind() == CXCursor_EnumDecl, return Utf8String()); + + const Type enumType = semanticParent.enumType(); + if (enumType.isUnsigned()) + return Utf8String::number(cursor.enumConstantUnsignedValue()); + return Utf8String::number(cursor.enumConstantValue()); +} + +Utf8String textForInclusionDirective(const Cursor &cursor) +{ + const CXFile includedFile = cursor.includedFile(); + const Utf8String fileName = ClangString(clang_getFileName(includedFile)); + + return QDir::toNativeSeparators(fileName.toString()); +} + +Utf8String textForAnyTypeAlias(const Cursor &cursor) +{ + // For a CXCursor_TypeAliasTemplateDecl the type of cursor/referenced + // is invalid, so we do not get the underlying type. This here solely + // reports the unresolved name instead of the empty string. + if (cursor.kind() == CXCursor_TypeAliasTemplateDecl) + return cursor.displayName(); + + return cursor.type().alias().utf8Spelling(); +} + +bool includeSizeForCursor(const Cursor &cursor) +{ + return cursor.isCompoundType() + || cursor.kind() == CXCursor_EnumDecl + || cursor.kind() == CXCursor_UnionDecl + || cursor.kind() == CXCursor_FieldDecl; +} + +Utf8String sizeInBytes(const Cursor &cursor) +{ + if (includeSizeForCursor(cursor)) { + bool ok = false; + const long long size = cursor.type().sizeOf(&ok); + if (ok) + return Utf8String::number(size); + } + + return Utf8String(); +} + +Cursor referencedCursor(const Cursor &cursor) +{ + // Query the referenced cursor directly instead of first testing with cursor.isReference(). + // cursor.isReference() reports false for e.g. CXCursor_DeclRefExpr or CXCursor_CallExpr + // although it returns a valid cursor. + const Cursor referenced = cursor.referenced(); + if (referenced.isValid()) + return referenced; + + const Cursor definition = cursor.definition(); + if (definition.isValid()) + return definition; + + return cursor; +} + +class ToolTipInfoCollector +{ +public: + ToolTipInfoCollector(UnsavedFiles &unsavedFiles, + const Utf8String &textCodecName, + const Utf8String &mainFilePath, + CXTranslationUnit cxTranslationUnit); + + ToolTipInfo collect(uint line, uint column) const; + +private: + Utf8String text(const Cursor &cursor, const Cursor &referenced) const; + Utf8String textForMacroExpansion(const Cursor &cursor) const; + Utf8String textForNamespaceAlias(const Cursor &cursor) const; + + ToolTipInfo qDocInfo(const Cursor &cursor) const; + + CXSourceLocation toCXSourceLocation(uint line, uint column) const; + + UnsavedFile unsavedFile(const Utf8String &filePath) const; + Utf8String lineRange(const Utf8String &filePath, unsigned fromLine, unsigned toLine) const; + +private: + UnsavedFiles &m_unsavedFiles; + const Utf8String m_textCodecName; + + const Utf8String m_mainFilePath; + CXTranslationUnit m_cxTranslationUnit = nullptr; + +}; + +ToolTipInfoCollector::ToolTipInfoCollector(UnsavedFiles &unsavedFiles, + const Utf8String &textCodecName, + const Utf8String &mainFilePath, + CXTranslationUnit cxTranslationUnit) + : m_unsavedFiles(unsavedFiles) + , m_textCodecName(textCodecName) + , m_mainFilePath(mainFilePath) + , m_cxTranslationUnit(cxTranslationUnit) +{ +} + +Utf8String ToolTipInfoCollector::text(const Cursor &cursor, const Cursor &referenced) const +{ + if (cursor.kind() == CXCursor_MacroExpansion) + return textForMacroExpansion(referenced); + + if (referenced.kind() == CXCursor_EnumConstantDecl) + return textForEnumConstantDecl(referenced); + + if (referenced.kind() == CXCursor_InclusionDirective) + return textForInclusionDirective(referenced); + + if (referenced.kind() == CXCursor_Namespace) + return qualificationPrefix(referenced) + referenced.spelling(); + + if (referenced.kind() == CXCursor_NamespaceAlias) + return textForNamespaceAlias(referenced); + + if (referenced.isAnyTypeAlias()) + return textForAnyTypeAlias(referenced); + + if (referenced.isFunctionLike()) + return textForFunctionLike(referenced); + + if (referenced.type().canonical().isBuiltinType()) + return referenced.type().canonical().builtinTypeToString(); + + if (referenced.kind() == CXCursor_VarDecl) + return referenced.type().spelling(); // e.g. "Zii" + + const Type referencedType = referenced.type(); + if (referencedType.isValid()) { + // Generally, the type includes the qualification but has this limitations: + // * namespace aliases are not resolved + // * outer class of a inner template class is not included + // The type includes the qualification, but not resolved namespace aliases. + + // For a CXType_Record, this also includes e.g. "const " as prefix. + return referencedType.canonical().utf8Spelling(); + } + + return displayName(referenced); +} + +Utf8String ToolTipInfoCollector::textForMacroExpansion(const Cursor &cursor) const +{ + QTC_ASSERT(cursor.kind() == CXCursor_MacroDefinition, return Utf8String()); + + const SourceRange sourceRange = cursor.sourceRange(); + const SourceLocation start = sourceRange.start(); + const SourceLocation end = sourceRange.end(); + + return lineRange(start.filePath(), start.line(), end.line()); +} + +Utf8String ToolTipInfoCollector::textForNamespaceAlias(const Cursor &cursor) const +{ + // TODO: Add some libclang API to get the aliased name straight away. + + CXToken *cxTokens = nullptr; + uint cxTokenCount = 0; + + clang_tokenize(m_cxTranslationUnit, cursor.cxSourceRange(), &cxTokens, &cxTokenCount); + + Utf8String aliasedName; + // Start at 3 in order to skip these tokens: namespace X = + for (uint i = 3; i < cxTokenCount; ++i) + aliasedName += ClangString(clang_getTokenSpelling(m_cxTranslationUnit, cxTokens[i])); + + clang_disposeTokens(m_cxTranslationUnit, cxTokens, cxTokenCount); + + return aliasedName; +} + +static Utf8String typeName(const Type &type) +{ + return type.declaration().spelling(); +} + +static Utf8String qdocMark(const Cursor &cursor) +{ + if (cursor.kind() == CXCursor_ClassTemplate) + return cursor.spelling(); + + if (cursor.type().kind() == CXType_Enum + || cursor.type().kind() == CXType_Typedef + || cursor.type().kind() == CXType_Record) + return typeName(cursor.type()); + + Utf8String text = cursor.displayName(); + if (cursor.kind() == CXCursor_FunctionDecl) { + // TODO: Remove this workaround by fixing this in + // libclang with the help of CXPrintingPolicy. + text.replace(Utf8StringLiteral("<>"), Utf8String()); + } + + return text; +} + +static ToolTipInfo::QdocCategory qdocCategory(const Cursor &cursor) +{ + if (cursor.isFunctionLike()) + return ToolTipInfo::Function; + + if (cursor.kind() == CXCursor_MacroDefinition) + return ToolTipInfo::Macro; + + if (cursor.kind() == CXCursor_EnumConstantDecl) + return ToolTipInfo::Enum; + + if (cursor.type().kind() == CXType_Enum) + return ToolTipInfo::Enum; + + if (cursor.kind() == CXCursor_InclusionDirective) + return ToolTipInfo::Brief; + + // TODO: Handle CXCursor_NamespaceAlias, too?! + if (cursor.kind() == CXCursor_Namespace) + return ToolTipInfo::ClassOrNamespace; + + if (cursor.isCompoundType()) + return ToolTipInfo::ClassOrNamespace; + + if (cursor.kind() == CXCursor_NamespaceAlias) + return ToolTipInfo::ClassOrNamespace; + + if (cursor.type().kind() == CXType_Typedef) + return ToolTipInfo::Typedef; + + if (cursor.type().kind() == CXType_Record) + return ToolTipInfo::ClassOrNamespace; + + if (cursor.kind() == CXCursor_TypeAliasTemplateDecl) + return ToolTipInfo::Typedef; + + if (cursor.kind() == CXCursor_ClassTemplate) + return ToolTipInfo::ClassOrNamespace; + + return ToolTipInfo::Unknown; +} + +static Utf8String name(const Cursor &cursor) +{ + if (cursor.type().kind() == CXType_Record || cursor.kind() == CXCursor_EnumDecl) + return typeName(cursor.type()); + + return cursor.spelling(); +} + +static Utf8StringVector qDocIdCandidates(const Cursor &cursor) +{ + Utf8StringVector components = qualificationPrefixAsVector(cursor); + if (components.isEmpty()) + return { name(cursor) }; + + components << name(cursor); + Utf8StringVector result; + Utf8String name; + for (auto it = components.rbegin(); it != components.rend(); ++it) { + if (name.isEmpty()) + name = *it; + else + name = *it + (Utf8StringLiteral("::") + name); + + result.prepend(name); + } + + return result; +} + +// TODO: Add libclang API for this?! +static bool isBuiltinOrPointerToBuiltin(const Type &type) +{ + Type theType = type; + + if (theType.isBuiltinType()) + return true; + + // TODO: Simplify + // TODO: Test with ** + while (theType.pointeeType().isValid()) { + theType = theType.pointeeType(); + if (theType.isBuiltinType()) + return true; + } + + return false; +} + +ToolTipInfo ToolTipInfoCollector::qDocInfo(const Cursor &cursor) const +{ + ToolTipInfo result; + + if (isBuiltinOrPointerToBuiltin(cursor.type())) + return result; + + result.setQdocIdCandidates(qDocIdCandidates(cursor)); + result.setQdocMark(qdocMark(cursor)); + result.setQdocCategory(qdocCategory(cursor)); + + if (cursor.type().kind() == CXType_Record) { + result.setQdocIdCandidates(qDocIdCandidates(cursor.type().declaration())); + return result; + } + + if (cursor.kind() == CXCursor_VarDecl || cursor.kind() == CXCursor_FieldDecl) { + result.setQdocMark(typeName(cursor.type())); + // maybe template instantiation + if (cursor.type().kind() == CXType_Unexposed && cursor.type().canonical().kind() == CXType_Record) { + result.setQdocIdCandidates(qDocIdCandidates(cursor.type().canonical().declaration())); + result.setQdocCategory(ToolTipInfo::ClassOrNamespace); + return result; + } + } + + // TODO: Handle also RValueReference() + if (cursor.type().isLValueReference()) { + const Cursor pointeeTypeDeclaration = cursor.type().pointeeType().declaration(); + result.setQdocIdCandidates(qDocIdCandidates(pointeeTypeDeclaration)); + result.setQdocMark(pointeeTypeDeclaration.spelling()); + result.setQdocCategory(qdocCategory(pointeeTypeDeclaration)); + return result; + } + + return result; +} + +CXSourceLocation ToolTipInfoCollector::toCXSourceLocation(uint line, uint column) const +{ + return clang_getLocation(m_cxTranslationUnit, + clang_getFile(m_cxTranslationUnit, + m_mainFilePath.constData()), + line, + column); +} + +UnsavedFile ToolTipInfoCollector::unsavedFile(const Utf8String &filePath) const +{ + const UnsavedFile &unsavedFile = m_unsavedFiles.unsavedFile(filePath); + if (!unsavedFile.filePath().isEmpty()) + return unsavedFile; + + // Create an unsaved file with the file content from disk. + // TODO: Make use of clang_getFileContents() instead of reading from disk. + QTextCodec *codec = QTextCodec::codecForName(m_textCodecName); + QByteArray fileContent; + QString errorString; + using namespace Utils; + const TextFileFormat::ReadResult readResult + = TextFileFormat::readFileUTF8(filePath.toString(), codec, &fileContent, &errorString); + if (readResult != TextFileFormat::ReadSuccess) { + qWarning() << "Failed to read file" << filePath << ":" << errorString; + return UnsavedFile(); + } + + return UnsavedFile(filePath, Utf8String::fromByteArray(fileContent)); +} + +Utf8String ToolTipInfoCollector::lineRange(const Utf8String &filePath, + unsigned fromLine, + unsigned toLine) const +{ + if (toLine < fromLine) + return Utf8String(); + + const UnsavedFile file = unsavedFile(filePath); + if (file.fileContent().isEmpty()) + return Utf8String(); + + return file.lineRange(fromLine, toLine); +} + +ToolTipInfo ToolTipInfoCollector::collect(uint line, uint column) const +{ + const Cursor cursor = clang_getCursor(m_cxTranslationUnit, toCXSourceLocation(line, column)); + if (!cursor.isValid()) + return ToolTipInfo(); // E.g. cursor on ifdeffed out range + + const Cursor referenced = referencedCursor(cursor); + QTC_CHECK(referenced.isValid()); + + ToolTipInfo info; + info.setText(text(cursor, referenced)); + info.setBriefComment(referenced.briefComment()); + + { + ToolTipInfo qDocToolTipInfo = qDocInfo(referenced); + info.setQdocIdCandidates(qDocToolTipInfo.qdocIdCandidates()); + info.setQdocMark(qDocToolTipInfo.qdocMark()); + info.setQdocCategory(qDocToolTipInfo.qdocCategory()); + } + + info.setSizeInBytes(sizeInBytes(cursor)); + + return info; +} + +} // anonymous namespace + +ToolTipInfo collectToolTipInfo(UnsavedFiles &unsavedFiles, + const Utf8String &textCodecName, + const Utf8String &mainFilePath, + CXTranslationUnit cxTranslationUnit, + uint line, + uint column) +{ + ToolTipInfoCollector collector(unsavedFiles, textCodecName, mainFilePath, cxTranslationUnit); + const ToolTipInfo info = collector.collect(line, column); + + return info; +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangbackend/source/clangtooltipinfocollector.h b/src/tools/clangbackend/source/clangtooltipinfocollector.h new file mode 100644 index 00000000000..8009aa8bf4a --- /dev/null +++ b/src/tools/clangbackend/source/clangtooltipinfocollector.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 + +#include + +#include + +namespace ClangBackEnd { + +class UnsavedFiles; + +ToolTipInfo collectToolTipInfo(UnsavedFiles &unsavedFiles, + const Utf8String &textCodecName, + const Utf8String &mainFilePath, + CXTranslationUnit cxTranslationUnit, + uint line, + uint column); + +} // namespace ClangBackEnd diff --git a/src/tools/clangbackend/source/clangtranslationunit.cpp b/src/tools/clangbackend/source/clangtranslationunit.cpp index 94827801136..da06999b614 100644 --- a/src/tools/clangbackend/source/clangtranslationunit.cpp +++ b/src/tools/clangbackend/source/clangtranslationunit.cpp @@ -27,6 +27,7 @@ #include "clangbackend_global.h" #include "clangreferencescollector.h" +#include "clangtooltipinfocollector.h" #include "clangtranslationunitupdater.h" #include "clangfollowsymbol.h" #include "clangfollowsymboljob.h" @@ -139,6 +140,20 @@ void TranslationUnit::extractDocumentAnnotations( skippedSourceRanges = this->skippedSourceRanges().toSourceRangeContainers(); } + +ToolTipInfo TranslationUnit::tooltip(UnsavedFiles &unsavedFiles, + const Utf8String &textCodecName, + uint line, + uint column) const +{ + return collectToolTipInfo(unsavedFiles, + textCodecName, + filePath(), + m_cxTranslationUnit, + line, + column); +} + ReferencesResult TranslationUnit::references(uint line, uint column, bool localReferences) const { return collectReferences(m_cxTranslationUnit, line, column, localReferences); diff --git a/src/tools/clangbackend/source/clangtranslationunit.h b/src/tools/clangbackend/source/clangtranslationunit.h index 76ba3f00551..150645cc362 100644 --- a/src/tools/clangbackend/source/clangtranslationunit.h +++ b/src/tools/clangbackend/source/clangtranslationunit.h @@ -41,6 +41,7 @@ class SkippedSourceRanges; class SourceLocation; class SourceRange; class SourceRangeContainer; +class ToolTipInfo; class TranslationUnitUpdateInput; class TranslationUnitUpdateResult; class UnsavedFiles; @@ -86,6 +87,10 @@ public: ReferencesResult references(uint line, uint column, bool localReferences = false) const; + ToolTipInfo tooltip(UnsavedFiles &unsavedFiles, + const Utf8String &textCodecName, + uint line, + uint column) const; DiagnosticSet diagnostics() const; SourceLocation sourceLocationAt(uint line, uint column) const; diff --git a/src/tools/clangbackend/source/clangtype.cpp b/src/tools/clangbackend/source/clangtype.cpp index 8fc09d8c4af..970b9452c1d 100644 --- a/src/tools/clangbackend/source/clangtype.cpp +++ b/src/tools/clangbackend/source/clangtype.cpp @@ -84,6 +84,16 @@ bool Type::isBuiltinType() const return cxType.kind >= CXType_FirstBuiltin && cxType.kind <= CXType_LastBuiltin; } +bool Type::isUnsigned() const +{ + return cxType.kind == CXType_UChar + || cxType.kind == CXType_UShort + || cxType.kind == CXType_UInt + || cxType.kind == CXType_ULong + || cxType.kind == CXType_ULongLong + || cxType.kind == CXType_UInt128; +} + Utf8String Type::utf8Spelling() const { return ClangString(clang_getTypeSpelling(cxType)); @@ -94,6 +104,83 @@ ClangString Type::spelling() const return ClangString(clang_getTypeSpelling(cxType)); } +static const char *builtinTypeToText(CXTypeKind kind) +{ + // CLANG-UPGRADE-CHECK: Check for added built-in types. + + switch (kind) { + case CXType_Void: + return "void"; + case CXType_Bool: + return "bool"; + + // See also ${CLANG_REPOSITORY}/lib/Sema/SemaChecking.cpp - IsSameCharType(). + case CXType_Char_U: + case CXType_UChar: + return "unsigned char"; + case CXType_Char_S: + case CXType_SChar: + return "signed char"; + + case CXType_Char16: + return "char16_t"; + case CXType_Char32: + return "char32_t"; + case CXType_WChar: + return "wchar_t"; + + case CXType_UShort: + return "unsigned short"; + case CXType_UInt: + return "unsigned int"; + case CXType_ULong: + return "unsigned long"; + case CXType_ULongLong: + return "unsigned long long"; + case CXType_Short: + return "short"; + + case CXType_Int: + return "int"; + case CXType_Long: + return "long"; + case CXType_LongLong: + return "long long"; + + case CXType_Float: + return "float"; + case CXType_Double: + return "double"; + case CXType_LongDouble: + return "long double"; + + case CXType_NullPtr: + return "nullptr_t"; + + // https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html + case CXType_Int128: return "__int128"; + case CXType_UInt128: return "unsigned __int128"; + + // https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html + case CXType_Float128: return "__float128"; + // CLANG-UPGRADE-CHECK: CXType_Float16 available with >= clang-6.0: +// case CXType_Float16: return "_Float16"; + + // https://www.khronos.org/registry/OpenCL/sdk/2.1/docs/man/xhtml/scalarDataTypes.html + case CXType_Half: + return "half"; + + default: + return ""; + } +} + +Utf8String Type::builtinTypeToString() const +{ + const char *text = builtinTypeToText(cxType.kind); + return Utf8String::fromByteArray(QByteArray::fromRawData(text, strlen(text))); +} + int Type::argumentCount() const { return clang_getNumArgTypes(cxType); @@ -129,6 +216,16 @@ Cursor Type::declaration() const return clang_getTypeDeclaration(cxType); } +long long Type::sizeOf(bool *isValid) const +{ + const long long size = clang_Type_getSizeOf(cxType); + *isValid = size != CXTypeLayoutError_Invalid + && size != CXTypeLayoutError_Incomplete + && size != CXTypeLayoutError_Dependent; + + return size; +} + CXTypeKind Type::kind() const { return cxType.kind; diff --git a/src/tools/clangbackend/source/clangtype.h b/src/tools/clangbackend/source/clangtype.h index f26fe080f6b..6be968d3901 100644 --- a/src/tools/clangbackend/source/clangtype.h +++ b/src/tools/clangbackend/source/clangtype.h @@ -53,9 +53,11 @@ public: bool isReferencingConstant() const; bool isOutputArgument() const; bool isBuiltinType() const; + bool isUnsigned() const; Utf8String utf8Spelling() const; ClangString spelling() const; + Utf8String builtinTypeToString() const; int argumentCount() const; Type alias() const; @@ -66,6 +68,8 @@ public: Cursor declaration() const; + long long sizeOf(bool *isValid) const; + CXTypeKind kind() const; private: diff --git a/src/tools/clangbackend/source/cursor.cpp b/src/tools/clangbackend/source/cursor.cpp index 6ad50307cdd..41a0465e7a0 100644 --- a/src/tools/clangbackend/source/cursor.cpp +++ b/src/tools/clangbackend/source/cursor.cpp @@ -158,6 +158,14 @@ bool Cursor::isTemplateLike() const Q_UNREACHABLE(); } +bool Cursor::isAnyTypeAlias() const +{ + const CXCursorKind k = kind(); + return k == CXCursor_TypeAliasDecl + || k == CXCursor_TypedefDecl + || k == CXCursor_TypeAliasTemplateDecl; +} + bool Cursor::hasFinalFunctionAttribute() const { bool hasFinal = false; @@ -248,11 +256,31 @@ Type Cursor::nonPointerTupe() const return typeResult; } +Type Cursor::enumType() const +{ + return clang_getEnumDeclIntegerType(cxCursor); +} + +long long Cursor::enumConstantValue() const +{ + return clang_getEnumConstantDeclValue(cxCursor); +} + +unsigned long long Cursor::enumConstantUnsignedValue() const +{ + return clang_getEnumConstantDeclUnsignedValue(cxCursor); +} + Cursor Cursor::specializedCursorTemplate() const { return clang_getSpecializedCursorTemplate(cxCursor); } +CXFile Cursor::includedFile() const +{ + return clang_getIncludedFile(cxCursor); +} + SourceLocation Cursor::sourceLocation() const { return clang_getCursorLocation(cxCursor); @@ -341,6 +369,11 @@ Cursor Cursor::functionBase() const return functionBaseCursor; } +Type Cursor::resultType() const +{ + return clang_getResultType(type().cxType); +} + Cursor Cursor::argument(int index) const { return clang_Cursor_getArgument(cxCursor, index); @@ -398,6 +431,11 @@ CXCursorKind Cursor::kind() const return clang_getCursorKind(cxCursor); } +CXCursor Cursor::cx() const +{ + return cxCursor; +} + bool operator==(const Cursor &first, const Cursor &second) { return clang_equalCursors(first.cxCursor, second.cxCursor); diff --git a/src/tools/clangbackend/source/cursor.h b/src/tools/clangbackend/source/cursor.h index 6520366b36d..bef5a006f4f 100644 --- a/src/tools/clangbackend/source/cursor.h +++ b/src/tools/clangbackend/source/cursor.h @@ -67,6 +67,7 @@ public: bool isFunctionLike() const; bool isConstructorOrDestructor() const; bool isTemplateLike() const; + bool isAnyTypeAlias() const; bool hasFinalFunctionAttribute() const; bool hasFinalClassAttribute() const; bool isUnexposed() const; @@ -81,6 +82,10 @@ public: Type type() const; Type nonPointerTupe() const; + Type enumType() const; + + long long enumConstantValue() const; + unsigned long long enumConstantUnsignedValue() const; SourceLocation sourceLocation() const; CXSourceLocation cxSourceLocation() const; @@ -92,17 +97,19 @@ public: Cursor definition() const; Cursor canonical() const; - Cursor alias() const; Cursor referenced() const; Cursor semanticParent() const; Cursor lexicalParent() const; Cursor functionBaseDeclaration() const; Cursor functionBase() const; + Type resultType() const; Cursor argument(int index) const; unsigned overloadedDeclarationsCount() const; Cursor overloadedDeclaration(unsigned index) const; Cursor specializedCursorTemplate() const; + CXFile includedFile() const; + void collectOutputArgumentRangesTo( std::vector &outputArgumentRanges) const; std::vector outputArgumentRanges() const; @@ -112,6 +119,8 @@ public: template void visit(VisitorCallback visitorCallback) const; + CXCursor cx() const; + private: CXCursor cxCursor; }; diff --git a/src/tools/clangbackend/source/unsavedfile.cpp b/src/tools/clangbackend/source/unsavedfile.cpp index 923d4456e8a..efcad4cad47 100644 --- a/src/tools/clangbackend/source/unsavedfile.cpp +++ b/src/tools/clangbackend/source/unsavedfile.cpp @@ -30,6 +30,8 @@ #include +#include + namespace ClangBackEnd { UnsavedFile::UnsavedFile() @@ -79,6 +81,25 @@ bool UnsavedFile::hasCharacterAt(uint line, uint column, char character) const return positionIsOk && hasCharacterAt(utf8Position, character); } +Utf8String UnsavedFile::lineRange(uint fromLine, uint toLine) const +{ + QTC_ASSERT(fromLine <= toLine, return Utf8String()); + + // Find start of first line + bool ok = false; + const uint fromPosition = toUtf8Position(fromLine, 1, &ok); + QTC_ASSERT(ok, return Utf8String()); + + // Find end of last line + uint toPosition = toUtf8Position(toLine, 1, &ok); + QTC_ASSERT(ok, return Utf8String()); + const uint endPosition = uint(m_fileContent.byteSize()); + while (toPosition < endPosition && m_fileContent.constData()[toPosition] != '\n') + ++toPosition; + + return m_fileContent.mid(int(fromPosition), int(toPosition - fromPosition)); +} + bool UnsavedFile::hasCharacterAt(uint position, char character) const { if (position < uint(m_fileContent.byteSize())) diff --git a/src/tools/clangbackend/source/unsavedfile.h b/src/tools/clangbackend/source/unsavedfile.h index 3021da89b5c..325139d240d 100644 --- a/src/tools/clangbackend/source/unsavedfile.h +++ b/src/tools/clangbackend/source/unsavedfile.h @@ -46,6 +46,7 @@ public: // 1-based line and column uint toUtf8Position(uint line, uint column, bool *ok) const; bool hasCharacterAt(uint line, uint column, char character) const; + Utf8String lineRange(uint fromLine, uint toLine) const; // 0-based position bool hasCharacterAt(uint position, char character) const; diff --git a/tests/unit/echoserver/echoclangcodemodelserver.cpp b/tests/unit/echoserver/echoclangcodemodelserver.cpp index 2c0fea98c93..38d2d395444 100644 --- a/tests/unit/echoserver/echoclangcodemodelserver.cpp +++ b/tests/unit/echoserver/echoclangcodemodelserver.cpp @@ -98,6 +98,11 @@ void EchoClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMess echoMessage(message); } +void EchoClangCodeModelServer::requestToolTip(const RequestToolTipMessage &message) +{ + echoMessage(message); +} + void EchoClangCodeModelServer::updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) { echoMessage(message); diff --git a/tests/unit/echoserver/echoclangcodemodelserver.h b/tests/unit/echoserver/echoclangcodemodelserver.h index 2dc8c30913a..d3452d2d321 100644 --- a/tests/unit/echoserver/echoclangcodemodelserver.h +++ b/tests/unit/echoserver/echoclangcodemodelserver.h @@ -47,6 +47,7 @@ public: void requestDocumentAnnotations(const RequestDocumentAnnotationsMessage &message) override; void requestReferences(const RequestReferencesMessage &message) override; void requestFollowSymbol(const RequestFollowSymbolMessage &message) override; + void requestToolTip(const RequestToolTipMessage &message) override; void updateVisibleTranslationUnits(const UpdateVisibleTranslationUnitsMessage &message) override; private: diff --git a/tests/unit/unittest/clangtooltipinfo-test.cpp b/tests/unit/unittest/clangtooltipinfo-test.cpp new file mode 100644 index 00000000000..4f6c9806496 --- /dev/null +++ b/tests/unit/unittest/clangtooltipinfo-test.cpp @@ -0,0 +1,628 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** 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 "googletest.h" +#include "rundocumentparse-utility.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using ::ClangBackEnd::ProjectPart; +using ::ClangBackEnd::SourceLocationContainer; +using ::ClangBackEnd::Document; +using ::ClangBackEnd::UnsavedFiles; +using ::ClangBackEnd::ToolTipInfo; +using ::ClangBackEnd::SourceRangeContainer; + +namespace { + +#define CHECK_MEMBER(actual, expected, memberName) \ + if (actual.memberName() != expected.memberName()) { \ + *result_listener << #memberName " is " + PrintToString(actual.memberName()) \ + << " and not " + PrintToString(expected.memberName()); \ + return false; \ + } + +MATCHER_P(IsToolTip, expected, std::string(negation ? "isn't" : "is") + PrintToString(expected)) +{ + CHECK_MEMBER(arg, expected, text); + CHECK_MEMBER(arg, expected, briefComment); + + CHECK_MEMBER(arg, expected, qdocIdCandidates); + CHECK_MEMBER(arg, expected, qdocMark); + CHECK_MEMBER(arg, expected, qdocCategory); + + CHECK_MEMBER(arg, expected, sizeInBytes); + + return true; +} + +MATCHER_P(IsQdocToolTip, expected, std::string(negation ? "isn't" : "is") + PrintToString(expected)) +{ + CHECK_MEMBER(arg, expected, qdocIdCandidates); + CHECK_MEMBER(arg, expected, qdocMark); + CHECK_MEMBER(arg, expected, qdocCategory); + + return true; +} + +#undef CHECK_MEMBER + +struct Data { + ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++14")}}; + ClangBackEnd::ProjectParts projects; + ClangBackEnd::UnsavedFiles unsavedFiles; + ClangBackEnd::Documents documents{projects, unsavedFiles}; + Document document{Utf8StringLiteral(TESTDATA_DIR "/tooltipinfo.cpp"), + projectPart, + {}, + documents}; + UnitTest::RunDocumentParse _1{document}; +}; + +class ToolTipInfo : public ::testing::Test +{ +protected: + ::ToolTipInfo tooltip(uint line, uint column) + { + return d->document.translationUnit().tooltip(d->unsavedFiles, + Utf8StringLiteral("UTF-8"), + line, + column); + } + + static void SetUpTestCase(); + static void TearDownTestCase(); + +private: + static std::unique_ptr d; +}; + +TEST_F(ToolTipInfo, LocalVariableInt) +{ + const ::ToolTipInfo actual = tooltip(3, 5); + + ASSERT_THAT(actual, IsToolTip(::ToolTipInfo(Utf8StringLiteral("int")))); +} + +TEST_F(ToolTipInfo, LocalVariablePointerToConstInt) +{ + const ::ToolTipInfo actual = tooltip(4, 5); + + ASSERT_THAT(actual, IsToolTip(::ToolTipInfo(Utf8StringLiteral("const int *")))); +} + +TEST_F(ToolTipInfo, LocalParameterVariableConstRefCustomType) +{ + ::ToolTipInfo expected(Utf8StringLiteral("const Foo &")); + expected.setQdocIdCandidates({Utf8StringLiteral("Foo")}); + expected.setQdocMark(Utf8StringLiteral("Foo")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(12, 12); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, LocalNonParameterVariableConstRefCustomType) +{ + ::ToolTipInfo expected(Utf8StringLiteral("const Foo")); + expected.setQdocIdCandidates({Utf8StringLiteral("Foo")}); + expected.setQdocMark(Utf8StringLiteral("Foo")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(14, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, MemberVariable) +{ + const ::ToolTipInfo actual = tooltip(12, 16); + + ASSERT_THAT(actual, IsToolTip(::ToolTipInfo(Utf8StringLiteral("int")))); +} + +TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(MemberFunctionCall_QualifiedName)) +{ + const ::ToolTipInfo actual = tooltip(21, 9); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("int Bar::mem()")); +} + +// ChangeLog: Show extra specifiers. For functions e.g.: virtual, inline, explicit, const, volatile +TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(MemberFunctionCall_ExtraSpecifiers)) +{ + const ::ToolTipInfo actual = tooltip(22, 9); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("virtual int Bar::virtualConstMem() const")); +} + +TEST_F(ToolTipInfo, MemberFunctionCall_qdocIdCandidates) +{ + const ::ToolTipInfo actual = tooltip(21, 9); + + ASSERT_THAT(actual.qdocIdCandidates(), ElementsAre(Utf8StringLiteral("Bar::mem"), + Utf8StringLiteral("mem"))); +} + +TEST_F(ToolTipInfo, MemberFunctionCall_qdocMark_FIXLIBCLANG_CHECKED) +{ + const ::ToolTipInfo actual = tooltip(21, 9); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("mem()")); +} + +// TODO: Check what is really needed for qdoc before implementing this one. +TEST_F(ToolTipInfo, DISABLED_MemberFunctionCall_qdocMark_extraSpecifiers) +{ + const ::ToolTipInfo actual = tooltip(22, 9); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("virtualConstMem() const")); +} + +TEST_F(ToolTipInfo, MemberFunctionCall_qdocCategory) +{ + const ::ToolTipInfo actual = tooltip(21, 9); + + ASSERT_THAT(actual.qdocCategory(), ::ToolTipInfo::Function); +} + +// TODO: Show the template parameter type, too: "template...)" +TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(TemplateFunctionCall)) +{ + const ::ToolTipInfo actual = tooltip(30, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("template<> void t(int foo)")); +} + +TEST_F(ToolTipInfo, TemplateFunctionCall_qdocIdCandidates) +{ + const ::ToolTipInfo actual = tooltip(30, 5); + + ASSERT_THAT(actual.qdocIdCandidates(), ElementsAre(Utf8StringLiteral("t"))); +} + +TEST_F(ToolTipInfo, TemplateFunctionCall_qdocMark_FIXLIBCLANG_CHECKED) +{ + const ::ToolTipInfo actual = tooltip(30, 5); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("t(int)")); +} + +TEST_F(ToolTipInfo, TemplateFunctionCall_qdocCategory) +{ + const ::ToolTipInfo actual = tooltip(30, 5); + + ASSERT_THAT(actual.qdocCategory(), ::ToolTipInfo::Function); +} + +TEST_F(ToolTipInfo, BriefComment) +{ + const ::ToolTipInfo actual = tooltip(41, 5); + + ASSERT_THAT(actual.briefComment(), Utf8StringLiteral("This is a crazy function.")); +} + +TEST_F(ToolTipInfo, Enum) +{ + ::ToolTipInfo expected(Utf8StringLiteral("EnumType")); + expected.setQdocIdCandidates({Utf8StringLiteral("EnumType")}); + expected.setQdocMark(Utf8StringLiteral("EnumType")); + expected.setQdocCategory(::ToolTipInfo::Enum); + + const ::ToolTipInfo actual = tooltip(49, 12); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, Enumerator) +{ + ::ToolTipInfo expected(Utf8StringLiteral("6")); + expected.setQdocIdCandidates({Utf8StringLiteral("Custom")}); + expected.setQdocMark(Utf8StringLiteral("EnumType")); + expected.setQdocCategory(::ToolTipInfo::Enum); + + const ::ToolTipInfo actual = tooltip(49, 22); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, TemplateTypeFromParameter) +{ + ::ToolTipInfo expected(Utf8StringLiteral("const Baz &")); + expected.setQdocIdCandidates({Utf8StringLiteral("Baz")}); + expected.setQdocMark(Utf8StringLiteral("Baz")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(55, 25); + + ASSERT_THAT(actual, IsQdocToolTip(expected)); +} + +TEST_F(ToolTipInfo, TemplateTypeFromNonParameter) +{ + ::ToolTipInfo expected(Utf8StringLiteral("Baz")); + expected.setQdocIdCandidates({Utf8StringLiteral("Baz")}); + expected.setQdocMark(Utf8StringLiteral("Baz")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(56, 19); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, IncludeDirective) +{ + ::ToolTipInfo expected(Utf8StringLiteral(TESTDATA_DIR"/tooltipinfo.h")); + expected.setQdocIdCandidates({Utf8StringLiteral("tooltipinfo.h")}); + expected.setQdocMark(Utf8StringLiteral("tooltipinfo.h")); + expected.setQdocCategory(::ToolTipInfo::Brief); + + const ::ToolTipInfo actual = tooltip(59, 11); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, MacroUse_WithMacroFromSameFile) +{ + const ::ToolTipInfo actual = tooltip(66, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("#define MACRO_FROM_MAINFILE(x) x + 3")); +} + +TEST_F(ToolTipInfo, MacroUse_WithMacroFromHeader) +{ + const ::ToolTipInfo actual = tooltip(67, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("#define MACRO_FROM_HEADER(x) x + \\\n x + \\\n x")); +} + +TEST_F(ToolTipInfo, MacroUse_qdoc) +{ + ::ToolTipInfo expected; + expected.setQdocIdCandidates({Utf8StringLiteral("MACRO_FROM_MAINFILE")}); + expected.setQdocMark(Utf8StringLiteral("MACRO_FROM_MAINFILE")); + expected.setQdocCategory(::ToolTipInfo::Macro); + + const ::ToolTipInfo actual = tooltip(66, 5); + + ASSERT_THAT(actual, IsQdocToolTip(expected)); +} + +TEST_F(ToolTipInfo, TypeNameIntroducedByUsingDirectiveIsQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("N::Muu")); + expected.setQdocIdCandidates({Utf8StringLiteral("N::Muu"), Utf8StringLiteral("Muu")}); + expected.setQdocMark(Utf8StringLiteral("Muu")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(77, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, TypeNameIntroducedByUsingDirectiveOfAliasIsResolvedAndQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("N::Muu")); + expected.setQdocIdCandidates({Utf8StringLiteral("N::Muu"), Utf8StringLiteral("Muu")}); + expected.setQdocMark(Utf8StringLiteral("Muu")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(82, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, TypeNameIntroducedByUsingDeclarationIsQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("N::Muu")); + expected.setQdocIdCandidates({Utf8StringLiteral("N::Muu"), Utf8StringLiteral("Muu")}); + expected.setQdocMark(Utf8StringLiteral("Muu")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(87, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, SizeForClassDefinition) +{ + const ::ToolTipInfo actual = tooltip(92, 8); + + ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("2")); +} + +TEST_F(ToolTipInfo, SizeForMemberField) +{ + const ::ToolTipInfo actual = tooltip(95, 10); + + ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("1")); +} + +TEST_F(ToolTipInfo, SizeForEnum) +{ + const ::ToolTipInfo actual = tooltip(97, 12); + + ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("4")); +} + +TEST_F(ToolTipInfo, SizeForUnion) +{ + const ::ToolTipInfo actual = tooltip(98, 7); + + ASSERT_THAT(actual.sizeInBytes(), Utf8StringLiteral("1")); +} + +TEST_F(ToolTipInfo, Namespace) +{ + ::ToolTipInfo expected(Utf8StringLiteral("X")); + expected.setQdocIdCandidates({Utf8StringLiteral("X")}); + expected.setQdocMark(Utf8StringLiteral("X")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(106, 11); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, NamespaceQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("X::Y")); + expected.setQdocIdCandidates({Utf8StringLiteral("X::Y"), Utf8StringLiteral("Y")}); + expected.setQdocMark(Utf8StringLiteral("Y")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(107, 11); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +// TODO: Show unresolved and resolved name, for F1 try both. +TEST_F(ToolTipInfo, TypeName_ResolveTypeDef) +{ + ::ToolTipInfo expected(Utf8StringLiteral("Ptr")); + expected.setQdocIdCandidates({Utf8StringLiteral("PtrFromTypeDef")}); + expected.setQdocMark(Utf8StringLiteral("PtrFromTypeDef")); + expected.setQdocCategory(::ToolTipInfo::Typedef); + + const ::ToolTipInfo actual = tooltip(122, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +// TODO: Show unresolved and resolved name, for F1 try both. +TEST_F(ToolTipInfo, TypeName_ResolveAlias) +{ + ::ToolTipInfo expected(Utf8StringLiteral("Ptr")); + expected.setQdocIdCandidates({Utf8StringLiteral("PtrFromTypeAlias")}); + expected.setQdocMark(Utf8StringLiteral("PtrFromTypeAlias")); + expected.setQdocCategory(::ToolTipInfo::Typedef); + + const ::ToolTipInfo actual = tooltip(123, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +// The referenced cursor is a CXCursor_TypeAliasTemplateDecl, its type is invalid +// and so probably clang_getTypedefDeclUnderlyingType() does not return anything useful. +// TODO: Fix the cursor's type or add new API in libclang for querying the template type alias. +TEST_F(ToolTipInfo, DISABLED_TypeName_ResolveTemplateTypeAlias) +{ + const ::ToolTipInfo actual = tooltip(124, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("Ptr")); +} + +TEST_F(ToolTipInfo, TypeName_ResolveTemplateTypeAlias_qdoc) +{ + ::ToolTipInfo expected; + expected.setQdocIdCandidates({Utf8StringLiteral("PtrFromTemplateTypeAlias")}); + expected.setQdocMark(Utf8StringLiteral("PtrFromTemplateTypeAlias")); + expected.setQdocCategory(::ToolTipInfo::Typedef); + + const ::ToolTipInfo actual = tooltip(124, 5); + + ASSERT_THAT(actual, IsQdocToolTip(expected)); +} + +TEST_F(ToolTipInfo, TemplateClassReference) +{ + ::ToolTipInfo expected(Utf8StringLiteral("Zii")); + expected.setQdocIdCandidates({Utf8StringLiteral("Zii")}); + expected.setQdocMark(Utf8StringLiteral("Zii")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(134, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, TemplateClassQualified) +{ + ::ToolTipInfo expected(Utf8StringLiteral("U::Yii")); + expected.setQdocIdCandidates({Utf8StringLiteral("U::Yii"), Utf8StringLiteral("Yii")}); + expected.setQdocMark(Utf8StringLiteral("Yii")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(135, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, ResolveNamespaceAliasForType) +{ + ::ToolTipInfo expected(Utf8StringLiteral("A::X")); + expected.setQdocIdCandidates({Utf8StringLiteral("A::X"), Utf8StringLiteral("X")}); + expected.setQdocMark(Utf8StringLiteral("X")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(144, 8); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +// TODO: Show unresolved and resolved name, for F1 try both. +TEST_F(ToolTipInfo, ResolveNamespaceAlias) +{ + ::ToolTipInfo expected(Utf8StringLiteral("A")); + expected.setQdocIdCandidates({Utf8StringLiteral("B")}); + expected.setQdocMark(Utf8StringLiteral("B")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + + const ::ToolTipInfo actual = tooltip(144, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, QualificationForTemplateClassInClassInNamespace) +{ + ::ToolTipInfo expected(Utf8StringLiteral("N::Outer::Inner")); + expected.setQdocIdCandidates({Utf8StringLiteral("N::Outer::Inner"), + Utf8StringLiteral("Outer::Inner"), + Utf8StringLiteral("Inner")}); + expected.setQdocMark(Utf8StringLiteral("Inner")); + expected.setQdocCategory(::ToolTipInfo::ClassOrNamespace); + expected.setSizeInBytes(Utf8StringLiteral("1")); + + const ::ToolTipInfo actual = tooltip(153, 16); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, Function) +{ + ::ToolTipInfo expected(Utf8StringLiteral("void f()")); + expected.setQdocIdCandidates({Utf8StringLiteral("f")}); + expected.setQdocMark(Utf8StringLiteral("f()")); + expected.setQdocCategory(::ToolTipInfo::Function); + + const ::ToolTipInfo actual = tooltip(165, 5); + + ASSERT_THAT(actual, IsToolTip(expected)); +} + +TEST_F(ToolTipInfo, Function_QualifiedName) +{ + const ::ToolTipInfo actual = tooltip(166, 8); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("void R::f()")); +} + +TEST_F(ToolTipInfo, Function_qdocIdCandidatesAreQualified) +{ + const ::ToolTipInfo actual = tooltip(166, 8); + + ASSERT_THAT(actual.qdocIdCandidates(), ElementsAre(Utf8StringLiteral("R::f"), + Utf8StringLiteral("f"))); +} + +TEST_F(ToolTipInfo, DISABLED_WITHOUT_PRETTYDECL_PATCH(Function_HasParameterName)) +{ + const ::ToolTipInfo actual = tooltip(167, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("void f(int param)")); +} + +// TODO: Implement with CXPrintingPolicy +TEST_F(ToolTipInfo, DISABLED_Function_HasDefaultArgument) +{ + const ::ToolTipInfo actual = tooltip(168, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("void z(int = 1)")); +} + +TEST_F(ToolTipInfo, Function_qdocMarkHasNoParameterName) +{ + const ::ToolTipInfo actual = tooltip(167, 5); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("f(int)")); +} + +TEST_F(ToolTipInfo, Function_qdocMarkHasNoDefaultArgument) +{ + const ::ToolTipInfo actual = tooltip(168, 5); + + ASSERT_THAT(actual.qdocMark(), Utf8StringLiteral("z(int)")); +} + +TEST_F(ToolTipInfo, AutoTypeBuiltin) +{ + const ::ToolTipInfo actual = tooltip(176, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("int")); +} + +// TODO: Test for qdoc entries, too. +TEST_F(ToolTipInfo, AutoTypeEnum) +{ + const ::ToolTipInfo actual = tooltip(177, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("EnumType")); +} + +// TODO: Test for qdoc entries, too. +TEST_F(ToolTipInfo, AutoTypeClassType) +{ + const ::ToolTipInfo actual = tooltip(178, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("Bar")); +} + +// TODO: Test for qdoc entries, too. +// TODO: Deduced template arguments work, too?! +TEST_F(ToolTipInfo, AutoTypeClassTemplateType) +{ + const ::ToolTipInfo actual = tooltip(179, 5); + + ASSERT_THAT(actual.text(), Utf8StringLiteral("Zii")); +} + +std::unique_ptr ToolTipInfo::d; + +void ToolTipInfo::SetUpTestCase() +{ + d.reset(new Data); +} + +void ToolTipInfo::TearDownTestCase() +{ + d.reset(); +} + +} // anonymous namespace diff --git a/tests/unit/unittest/conditionally-disabled-tests.h b/tests/unit/unittest/conditionally-disabled-tests.h index 27e6fe173b2..8f55db10d7a 100644 --- a/tests/unit/unittest/conditionally-disabled-tests.h +++ b/tests/unit/unittest/conditionally-disabled-tests.h @@ -33,3 +33,9 @@ #else # define DISABLED_ON_WINDOWS(x) x #endif + +#ifdef IS_PRETTY_DECL_SUPPORTED +# define DISABLED_WITHOUT_PRETTYDECL_PATCH(x) x +#else +# define DISABLED_WITHOUT_PRETTYDECL_PATCH(x) DISABLED_##x +#endif diff --git a/tests/unit/unittest/data/tooltipinfo.cpp b/tests/unit/unittest/data/tooltipinfo.cpp new file mode 100644 index 00000000000..1945577b635 --- /dev/null +++ b/tests/unit/unittest/data/tooltipinfo.cpp @@ -0,0 +1,180 @@ +void f(int foo, const int *cfoo) +{ + foo++; + cfoo++; +} + + + +struct Foo { int member = 0; }; +int g(const Foo &foo) +{ + return foo.member; + const Foo bar; + bar; +} + +struct Bar { virtual ~Bar(); int mem(){} virtual int virtualConstMem() const; }; +void h(const Foo &foo, Bar &bar) +{ + g(foo); + bar.mem(); + bar.virtualConstMem(); +} + + +template +void t(int foo) { (void)foo; } +void c() +{ + t(3); +} + + + +/** + * \brief This is a crazy function. + */ +void documentedFunction(); +void d() +{ + documentedFunction(); +} + + + +enum EnumType { V1, V2, Custom = V2 + 5 }; +EnumType e() +{ + return EnumType::Custom; +} + + + +template struct Baz { T member; }; +void t2(const Baz &b) { + Baz baz; baz = b; +} + +#include "tooltipinfo.h" + + + +#define MACRO_FROM_MAINFILE(x) x + 3 +void foo() +{ + MACRO_FROM_MAINFILE(7); + MACRO_FROM_HEADER(7); +} + + + +namespace N { struct Muu{}; } +namespace G = N; +void o() +{ + using namespace N; + Muu muu; (void)muu; +} +void n() +{ + using namespace G; + Muu muu; (void)muu; +} +void q() +{ + using N::Muu; + Muu muu; (void)muu; +} + + + +struct Sizes +{ + char memberChar1; + char memberChar2; +}; +enum class FancyEnumType { V1, V2 }; +union Union +{ + char memberChar1; + char memberChar2; +}; + + + +namespace X { +namespace Y { +} +} + + + +template struct Ptr {}; +struct Nuu {}; + +typedef Ptr PtrFromTypeDef; +using PtrFromTypeAlias = Ptr; +template using PtrFromTemplateTypeAlias = Ptr; + +void y() +{ + PtrFromTypeDef b; (void)b; + PtrFromTypeAlias a; (void)a; + PtrFromTemplateTypeAlias c; (void)c; +} + + + +template struct Zii {}; +namespace U { template struct Yii {}; } +void mc() +{ + using namespace U; + Zii zii; (void) zii; + Yii yii; (void) yii; +} + + + +namespace A { struct X {}; } +namespace B = A; +void ab() +{ + B::X x; (void)x; +} + + + +namespace N { +struct Outer +{ + template struct Inner {}; + Inner inner; +}; +} + + + +void f(); +namespace R { void f(); } +void f(int param); +void z(int = 1); +void user() +{ + f(); + R::f(); + f(1); + z(); +} + + + + +void autoTypes() +{ + auto a = 3; (void)a; + auto b = EnumType::V1; (void)b; + auto c = Bar(); (void)c; + auto d = Zii(); (void)d; +} diff --git a/tests/unit/unittest/data/tooltipinfo.h b/tests/unit/unittest/data/tooltipinfo.h new file mode 100644 index 00000000000..47d3bb92e75 --- /dev/null +++ b/tests/unit/unittest/data/tooltipinfo.h @@ -0,0 +1,3 @@ +#define MACRO_FROM_HEADER(x) x + \ + x + \ + x diff --git a/tests/unit/unittest/dummyclangipcclient.h b/tests/unit/unittest/dummyclangipcclient.h index 3908f9e89f2..e840b0a6c7a 100644 --- a/tests/unit/unittest/dummyclangipcclient.h +++ b/tests/unit/unittest/dummyclangipcclient.h @@ -38,4 +38,5 @@ public: void documentAnnotationsChanged(const ClangBackEnd::DocumentAnnotationsChangedMessage &) override {} void references(const ClangBackEnd::ReferencesMessage &) override {} void followSymbol(const ClangBackEnd::FollowSymbolMessage &) override {} + void tooltip(const ClangBackEnd::ToolTipMessage &) override {} }; diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 2c106ec0e53..1bcf5f2b07d 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include @@ -269,6 +270,17 @@ std::ostream &operator<<(std::ostream &os, const ReferencesMessage &message) return os; } +std::ostream &operator<<(std::ostream &os, const ToolTipMessage &message) +{ + os << "(" + << message.fileContainer() << ", " + << message.ticketNumber() << ", " + << message.toolTipInfo() << ", " + << ")"; + + return os; +} + std::ostream &operator<<(std::ostream &os, const EchoMessage &/*message*/) { return os << "()"; @@ -385,7 +397,8 @@ std::ostream &operator<<(std::ostream &os, const FileContainer &container) << container.filePath() << ", " << container.projectPartId() << ", " << container.fileArguments() << ", " - << container.documentRevision(); + << container.documentRevision() << ", " + << container.textCodecName(); if (container.hasUnsavedFileContent()) os << ", " @@ -552,6 +565,37 @@ std::ostream &operator<<(std::ostream &os, const RequestReferencesMessage &messa return os; } +std::ostream &operator<<(std::ostream &out, const RequestToolTipMessage &message) +{ + out << "(" + << message.fileContainer() << ", " + << message.ticketNumber() << ", " + << message.line() << ", " + << message.column() << ", " + << ")"; + + return out; +} + +std::ostream &operator<<(std::ostream &os, const ToolTipInfo::QdocCategory category) +{ + return os << qdocCategoryToString(category); +} + +std::ostream &operator<<(std::ostream &out, const ToolTipInfo &info) +{ + out << "(" + << info.m_text << ", " + << info.m_briefComment << ", " + << info.m_qdocIdCandidates << ", " + << info.m_qdocMark << ", " + << info.m_qdocCategory + << info.m_sizeInBytes << ", " + << ")"; + + return out; +} + std::ostream &operator<<(std::ostream &os, const RequestSourceLocationsForRenamingMessage &message) { diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index e08b4b33c0b..d58daaf40c2 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -73,6 +73,7 @@ class CodeCompletedMessage; class EchoMessage; class DocumentAnnotationsChangedMessage; class ReferencesMessage; +class ToolTipMessage; class FollowSymbolMessage; class CompleteCodeMessage; class EndMessage; @@ -97,6 +98,7 @@ class RemovePchProjectPartsMessage; class RequestDocumentAnnotationsMessage; class RequestFollowSymbolMessage; class RequestReferencesMessage; +class RequestToolTipMessage; class RequestSourceLocationsForRenamingMessage; class RequestSourceRangesAndDiagnosticsForQueryMessage; class RequestSourceRangesForQueryMessage; @@ -114,6 +116,7 @@ class UpdateVisibleTranslationUnitsMessage; class FilePath; class TokenInfo; class TokenInfos; +class ToolTipInfo; std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry); std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths); @@ -127,6 +130,7 @@ std::ostream &operator<<(std::ostream &out, const CodeCompletedMessage &message) std::ostream &operator<<(std::ostream &out, const EchoMessage &message); std::ostream &operator<<(std::ostream &out, const DocumentAnnotationsChangedMessage &message); std::ostream &operator<<(std::ostream &out, const ReferencesMessage &message); +std::ostream &operator<<(std::ostream &out, const ToolTipMessage &message); std::ostream &operator<<(std::ostream &out, const FollowSymbolMessage &message); std::ostream &operator<<(std::ostream &out, const CompleteCodeMessage &message); std::ostream &operator<<(std::ostream &out, const EndMessage &message); @@ -153,6 +157,8 @@ std::ostream &operator<<(std::ostream &out, const RemovePchProjectPartsMessage & std::ostream &operator<<(std::ostream &out, const RequestDocumentAnnotationsMessage &message); std::ostream &operator<<(std::ostream &out, const RequestFollowSymbolMessage &message); std::ostream &operator<<(std::ostream &out, const RequestReferencesMessage &message); +std::ostream &operator<<(std::ostream &out, const RequestToolTipMessage &message); +std::ostream &operator<<(std::ostream &out, const ToolTipInfo &info); std::ostream &operator<<(std::ostream &out, const RequestSourceLocationsForRenamingMessage &message); std::ostream &operator<<(std::ostream &out, const RequestSourceRangesAndDiagnosticsForQueryMessage &message); std::ostream &operator<<(std::ostream &out, const RequestSourceRangesForQueryMessage &message); diff --git a/tests/unit/unittest/mockclangcodemodelclient.h b/tests/unit/unittest/mockclangcodemodelclient.h index 2e287909ddf..3b5a3cfbf5a 100644 --- a/tests/unit/unittest/mockclangcodemodelclient.h +++ b/tests/unit/unittest/mockclangcodemodelclient.h @@ -45,4 +45,6 @@ public: void(const ClangBackEnd::ReferencesMessage &message)); MOCK_METHOD1(followSymbol, void(const ClangBackEnd::FollowSymbolMessage &message)); + MOCK_METHOD1(tooltip, + void(const ClangBackEnd::ToolTipMessage &message)); }; diff --git a/tests/unit/unittest/mockclangcodemodelserver.h b/tests/unit/unittest/mockclangcodemodelserver.h index 8b6c66b2a33..468f683bf53 100644 --- a/tests/unit/unittest/mockclangcodemodelserver.h +++ b/tests/unit/unittest/mockclangcodemodelserver.h @@ -55,6 +55,8 @@ public: void(const ClangBackEnd::RequestReferencesMessage &message)); MOCK_METHOD1(requestFollowSymbol, void(const ClangBackEnd::RequestFollowSymbolMessage &message)); + MOCK_METHOD1(requestToolTip, + void(const ClangBackEnd::RequestToolTipMessage &message)); MOCK_METHOD1(updateVisibleTranslationUnits, void(const ClangBackEnd::UpdateVisibleTranslationUnitsMessage &message)); }; diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index a16a13e88bf..b6a698361ae 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -118,6 +118,7 @@ SOURCES += \ clangstring-test.cpp \ clangsupportivetranslationunitinitializer-test.cpp \ clangsuspenddocumentjob-test.cpp \ + clangtooltipinfo-test.cpp \ clangtranslationunits-test.cpp \ clangtranslationunit-test.cpp \ clangupdatedocumentannotationsjob-test.cpp \ diff --git a/tests/unit/unittest/unsavedfile-test.cpp b/tests/unit/unittest/unsavedfile-test.cpp index 05783a33c32..7e4d3dae685 100644 --- a/tests/unit/unittest/unsavedfile-test.cpp +++ b/tests/unit/unittest/unsavedfile-test.cpp @@ -203,4 +203,32 @@ TEST_F(UnsavedFile, HasCharacterForLastLineColumn) ASSERT_TRUE(unsavedFile.hasCharacterAt(1, 7, 't')); } +TEST_F(UnsavedFile, LineRangeForInvalidLines) +{ + ::UnsavedFile unsavedFile(filePath, fileContent); + + ASSERT_THAT(unsavedFile.lineRange(2, 1), Utf8String()); +} + +TEST_F(UnsavedFile, LineRangeForSingleLine) +{ + ::UnsavedFile unsavedFile(filePath, Utf8StringLiteral("foo")); + + ASSERT_THAT(unsavedFile.lineRange(1, 1), Utf8StringLiteral("foo")); +} + +TEST_F(UnsavedFile, LineRangeForSingleLineInMultipleLines) +{ + ::UnsavedFile unsavedFile(filePath, Utf8StringLiteral("foo\nbar\n\baz")); + + ASSERT_THAT(unsavedFile.lineRange(2, 2), Utf8StringLiteral("bar")); +} + +TEST_F(UnsavedFile, LineRangeForTwoLines) +{ + ::UnsavedFile unsavedFile(filePath, Utf8StringLiteral("foo\nbar\n\baz")); + + ASSERT_THAT(unsavedFile.lineRange(2, 3), Utf8StringLiteral("bar\n\baz")); +} + } // anonymous namespace From aaaa543a3250ab80e786fac8e26ea0d42ad8c927 Mon Sep 17 00:00:00 2001 From: Andre Hartmann Date: Tue, 26 Dec 2017 21:41:23 +0100 Subject: [PATCH 13/16] Locator: Allow simple calculations by using QJSEngine Task-number: QTCREATORBUG-14380 Change-Id: I807441ce00991856b3510a6793b454eb3c6a6c30 Reviewed-by: Orgad Shaneh Reviewed-by: Eike Ziller --- src/plugins/coreplugin/coreplugin.qbs | 2 + .../coreplugin/locator/javascriptfilter.cpp | 123 ++++++++++++++++++ .../coreplugin/locator/javascriptfilter.h | 58 +++++++++ src/plugins/coreplugin/locator/locator.cpp | 6 + src/plugins/coreplugin/locator/locator.h | 2 + src/plugins/coreplugin/locator/locator.pri | 8 +- 6 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 src/plugins/coreplugin/locator/javascriptfilter.cpp create mode 100644 src/plugins/coreplugin/locator/javascriptfilter.h diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index 109993bb115..ce47658daad 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -343,6 +343,8 @@ Project { "filesystemfilter.ui", "ilocatorfilter.cpp", "ilocatorfilter.h", + "javascriptfilter.cpp", + "javascriptfilter.h", "locatorconstants.h", "locatorfiltersfilter.cpp", "locatorfiltersfilter.h", diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp new file mode 100644 index 00000000000..02803ecf728 --- /dev/null +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Andre Hartmann +** 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 "javascriptfilter.h" + +#include +#include +#include + +namespace Core { +namespace Internal { + +JavaScriptFilter::JavaScriptFilter() +{ + setId("JavaScriptFilter"); + setDisplayName(tr("Evaluate JavaScript")); + setIncludedByDefault(false); + setShortcutString("="); +} + +JavaScriptFilter::~JavaScriptFilter() +{ +} + +void JavaScriptFilter::prepareSearch(const QString &entry) +{ + Q_UNUSED(entry); + + setupEngine(); +} + +QList JavaScriptFilter::matchesFor( + QFutureInterface &future, const QString &entry) +{ + Q_UNUSED(future); + + const QString result = m_engine->evaluate(entry).toString(); + const QString expression = entry + " = " + result; + + QList entries; + entries.append({this, expression, QVariant()}); + entries.append({this, tr("Copy to clipboard: %1").arg(result), result}); + entries.append({this, tr("Copy to clipboard: %1").arg(expression), expression}); + + return entries; +} + +void JavaScriptFilter::accept(Core::LocatorFilterEntry selection, QString *newText, + int *selectionStart, int *selectionLength) const +{ + Q_UNUSED(newText); + Q_UNUSED(selectionStart); + Q_UNUSED(selectionLength); + + if (selection.internalData.isNull()) + return; + + QClipboard *clipboard = QGuiApplication::clipboard(); + clipboard->setText(selection.internalData.toString()); +} + +void JavaScriptFilter::refresh(QFutureInterface &future) +{ + Q_UNUSED(future); + // Nothing to refresh +} + +void JavaScriptFilter::setupEngine() +{ + if (m_engine) + return; + + m_engine = new QJSEngine(this); + m_engine->evaluate( + "function abs(x) { return Math.abs(x); }\n" + "function acos(x) { return Math.acos(x); }\n" + "function asin(x) { return Math.asin(x); }\n" + "function atan(x) { return Math.atan(x); }\n" + "function atan2(x, y) { return Math.atan2(x, y); }\n" + "function bin(x) { return '0b' + x.toString(2); }\n" + "function ceil(x) { return Math.ceil(x); }\n" + "function cos(x) { return Math.cos(x); }\n" + "function exp(x) { return Math.exp(x); }\n" + "function e() { return Math.E; }\n" + "function floor(x) { return Math.floor(x); }\n" + "function hex(x) { return '0x' + x.toString(16); }\n" + "function log(x) { return Math.log(x); }\n" + "function max(x, y) { return Math.max(x, y); }\n" + "function min(x, y) { return Math.min(x, y); }\n" + "function oct(x) { return '0' + x.toString(8); }\n" + "function pi() { return Math.PI; }\n" + "function pow(x, y) { return Math.pow(x, y); }\n" + "function random() { return Math.random(); }\n" + "function round(x) { return Math.round(x); }\n" + "function sin(x) { return Math.sin(x); }\n" + "function sqrt(x) { return Math.sqrt(x); }\n" + "function tan(x) { return Math.tan(x); }\n"); +} + +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/locator/javascriptfilter.h b/src/plugins/coreplugin/locator/javascriptfilter.h new file mode 100644 index 00000000000..50f5e85c3b1 --- /dev/null +++ b/src/plugins/coreplugin/locator/javascriptfilter.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Andre Hartmann +** 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 + +QT_BEGIN_NAMESPACE +class QJSEngine; +QT_END_NAMESPACE + +namespace Core { +namespace Internal { + +class JavaScriptFilter : public Core::ILocatorFilter +{ + Q_OBJECT +public: + JavaScriptFilter(); + ~JavaScriptFilter(); + + virtual void prepareSearch(const QString &entry) override; + QList matchesFor(QFutureInterface &future, + const QString &entry) override; + void accept(Core::LocatorFilterEntry selection, QString *newText, + int *selectionStart, int *selectionLength) const override; + void refresh(QFutureInterface &future) override; + +private: + void setupEngine(); + + QJSEngine *m_engine = nullptr; +}; + +} // namespace Internal +} // namespace Core diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index 6daab8026e8..e57f20241ac 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -27,6 +27,7 @@ #include "externaltoolsfilter.h" #include "filesystemfilter.h" +#include "javascriptfilter.h" #include "locatorconstants.h" #include "locatorfiltersfilter.h" #include "locatormanager.h" @@ -75,11 +76,13 @@ Locator::Locator() Locator::~Locator() { + m_corePlugin->removeObject(m_javaScriptFilter); m_corePlugin->removeObject(m_openDocumentsFilter); m_corePlugin->removeObject(m_fileSystemFilter); m_corePlugin->removeObject(m_executeFilter); m_corePlugin->removeObject(m_settingsPage); m_corePlugin->removeObject(m_externalToolsFilter); + delete m_javaScriptFilter; delete m_openDocumentsFilter; delete m_fileSystemFilter; delete m_executeFilter; @@ -119,6 +122,9 @@ void Locator::initialize(CorePlugin *corePlugin, const QStringList &, QString *) new LocatorManager(this); + m_javaScriptFilter = new JavaScriptFilter; + m_corePlugin->addObject(m_javaScriptFilter); + m_openDocumentsFilter = new OpenDocumentsFilter; m_corePlugin->addObject(m_openDocumentsFilter); diff --git a/src/plugins/coreplugin/locator/locator.h b/src/plugins/coreplugin/locator/locator.h index 325bcc11304..5d5d379a887 100644 --- a/src/plugins/coreplugin/locator/locator.h +++ b/src/plugins/coreplugin/locator/locator.h @@ -42,6 +42,7 @@ namespace Internal { class CorePlugin; class OpenDocumentsFilter; class FileSystemFilter; +class JavaScriptFilter; class LocatorSettingsPage; class ExternalToolsFilter; @@ -85,6 +86,7 @@ private: QList m_customFilters; QMap m_filterActionMap; QTimer m_refreshTimer; + JavaScriptFilter *m_javaScriptFilter = nullptr; OpenDocumentsFilter *m_openDocumentsFilter = nullptr; FileSystemFilter *m_fileSystemFilter = nullptr; ExecuteFilter *m_executeFilter = nullptr; diff --git a/src/plugins/coreplugin/locator/locator.pri b/src/plugins/coreplugin/locator/locator.pri index e80765bfc5f..183d7fde515 100644 --- a/src/plugins/coreplugin/locator/locator.pri +++ b/src/plugins/coreplugin/locator/locator.pri @@ -1,3 +1,5 @@ +QT *= qml + HEADERS += \ $$PWD/locator.h \ $$PWD/commandlocator.h \ @@ -13,7 +15,8 @@ HEADERS += \ $$PWD/executefilter.h \ $$PWD/locatorsearchutils.h \ $$PWD/locatorsettingspage.h \ - $$PWD/externaltoolsfilter.h + $$PWD/externaltoolsfilter.h \ + $$PWD/javascriptfilter.h SOURCES += \ $$PWD/locator.cpp \ @@ -29,7 +32,8 @@ SOURCES += \ $$PWD/executefilter.cpp \ $$PWD/locatorsearchutils.cpp \ $$PWD/locatorsettingspage.cpp \ - $$PWD/externaltoolsfilter.cpp + $$PWD/externaltoolsfilter.cpp \ + $$PWD/javascriptfilter.cpp FORMS += \ $$PWD/filesystemfilter.ui \ From a26fecf8515ea8d61bb34651edcf7d1bc2aa89c7 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 16 Jan 2018 14:35:46 +0100 Subject: [PATCH 14/16] Debugger: Only raise watchers window if debugger is running Otherwise you run into a soft assert if you load a session that had watchers. Change-Id: Ib3566e7a8b26d953a904d6eeee536348afba9d62 Reviewed-by: hjk --- src/plugins/debugger/debuggerplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index a71127e38f0..e0fa782c390 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -3179,7 +3179,8 @@ QWidget *mainWindow() void raiseWatchersWindow() { - return dd->m_mainWindow->raiseDock(DOCKWIDGET_WATCHERS); + if (currentEngine()->state() != DebuggerNotReady) + dd->m_mainWindow->raiseDock(DOCKWIDGET_WATCHERS); } bool isRegistersWindowVisible() From 351f355b69632038f996d2d7039903d10f82c003 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Tue, 16 Jan 2018 21:59:40 +0200 Subject: [PATCH 15/16] ClangSupport: Add 2 missing exports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following GCC warnings: In file included from .../clangpchmanagerbackend/clangpchmanagerbackendmain.cpp:26:0: .../clangsupport/clangpathwatcher.h: In instantiation of ‘class ClangBackEnd::ClangPathWatcher’: .../clangpchmanagerbackend/clangpchmanagerbackendmain.cpp:114:78: required from here .../clangsupport/clangpathwatcher.h:80:7: warning: ‘ClangBackEnd::ClangPathWatcher’ declared with greater visibility than the type of its field ‘ClangBackEnd::ClangPathWatcher::m_idCache’ [-Wattributes] class ClangPathWatcher : public ClangPathWatcherInterface ^~~~~~~~~~~~~~~~ Change-Id: I8c6bc30e80da50b631d272ff7c2120cf706548aa Reviewed-by: Nikolai Kosjar --- src/libs/clangsupport/clangpathwatcher.h | 2 +- src/libs/clangsupport/filepathcache.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/clangsupport/clangpathwatcher.h b/src/libs/clangsupport/clangpathwatcher.h index 13e026ee092..2b9d517a6ca 100644 --- a/src/libs/clangsupport/clangpathwatcher.h +++ b/src/libs/clangsupport/clangpathwatcher.h @@ -77,7 +77,7 @@ using IdCache = StringCache -class ClangPathWatcher : public ClangPathWatcherInterface +class CLANGSUPPORT_EXPORT ClangPathWatcher : public ClangPathWatcherInterface { public: ClangPathWatcher(FilePathCachingInterface &pathCache, diff --git a/src/libs/clangsupport/filepathcache.h b/src/libs/clangsupport/filepathcache.h index 0e8fa7e4dfe..81bc3f40cc8 100644 --- a/src/libs/clangsupport/filepathcache.h +++ b/src/libs/clangsupport/filepathcache.h @@ -36,7 +36,7 @@ namespace ClangBackEnd { template -class FilePathCache +class CLANGSUPPORT_EXPORT FilePathCache { using DirectoryPathCache = StringCache Date: Wed, 17 Jan 2018 08:41:04 +0100 Subject: [PATCH 16/16] TextEditor: Remove left-over qDebugs() Change-Id: Ia5277b1eb40d35c59b2de09c88b44b180375a64f Reviewed-by: Christian Stenger --- src/plugins/texteditor/texteditor.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 4b2b428f019..c3fb788d25b 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -309,7 +309,6 @@ public: const int documentRevision = textCursor.document()->revision(); const int position = Text::wordStartCursor(textCursor).position(); if (m_lastHandlerInfo.applies(documentRevision, position)) { - qDebug() << "Last handler applies, showing it"; m_lastHandlerInfo.handler->showToolTip(m_widget, point, /*decorate=*/ false); return; } @@ -365,7 +364,6 @@ public: // All were queried, run the best if (m_bestHandler) { - qDebug() << "setting last handler info:" << m_documentRevision << m_position; m_lastHandlerInfo = LastHandlerInfo(m_bestHandler, m_documentRevision, m_position); m_bestHandler->showToolTip(m_widget, m_point); }