diff --git a/app/org.kde.kdevelop_ps.desktop b/app/org.kde.kdevelop_ps.desktop index 15098afbc2..dd472d8c10 100644 --- a/app/org.kde.kdevelop_ps.desktop +++ b/app/org.kde.kdevelop_ps.desktop @@ -1,69 +1,70 @@ [Desktop Entry] Type=Application Exec=kdevelop --ps MimeType= Icon=kdevelop Terminal=false Name=KDevelop (Pick Session) Name[ca]=KDevelop (Selecció de sessió) Name[ca@valencia]=KDevelop (Selecció de sessió) Name[cs]=KDevelop (Zvolte sezení) Name[de]=KDevelop (Sitzung auswählen) Name[el]=KDevelop (Επιλογή συνεδρίας) Name[en_GB]=KDevelop (Pick Session) Name[es]=KDevelop (escoger sesión) Name[et]=KDevelop (seansi valimine) Name[fi]=KDevelop (valitse istunto) Name[fr]=KDevelop (choisissez une session) Name[gl]=KDevelop (escolla a sesión) Name[hu]=KDevelop (munkamenet felvétele) Name[it]=KDevelop (Scegliere la sessione) Name[nl]=KDevelop (pak een sessie) Name[pl]=KDevelop (Wybór sesji) Name[pt]=KDevelop (Seleccionar uma Sessão) Name[pt_BR]=KDevelop (selecionar uma sessão) Name[ru]=KDevelop (с выбором сеанса) Name[sk]=KDevelop (zvoliť sedenie) Name[sl]=KDevelop (izbor seje) Name[sv]=KDevelop (välj session) Name[tr]=KDevelop (Oturum Seçin) Name[uk]=KDevelop (Вибір сеансу) Name[x-test]=xxKDevelop (Pick Session)xx Name[zh_CN]=KDevelop (选择会话) GenericName=Integrated Development Environment (Pick Session to start with) GenericName[ar]=بيئة تطوير متكاملة (انتقِ جلسةً للبدء بها) GenericName[bs]=Integrisano razvojno okruženje (odaberite sesiju za započeti) GenericName[ca]=Entorn integrat de desenvolupament (Seleccioneu una sessió) GenericName[ca@valencia]=Entorn integrat de desenvolupament (Seleccioneu una sessió) GenericName[cs]=Integrované Vývojové Prostředí (Zvolte si relaci, se kterou si přejete začít) GenericName[da]=Integreret udviklingsmiljø (IDE) (vælg session at starte med) GenericName[de]=Integrierte Entwicklungsumgebung (zu startende Sitzung auswählen) GenericName[el]=Ολοκληρωμένο περιβάλλον ανάπτυξης (Επιλογή συνεδρίας για εκκίνηση) GenericName[en_GB]=Integrated Development Environment (Pick Session to start with) GenericName[es]=Entorno de desarrollo integrado (escoger sesión con la que empezar) GenericName[et]=Integreeritud arenduskeskkond (seansi valimine alustamiseks) GenericName[fi]=Integroitu kehitysympäristö (valitse aloitettava istunto) GenericName[fr]=Environnement de Développement Intégré (choix d'une session avec laquelle démarrer) GenericName[ga]=Timpeallacht Chomhtháite Fhorbartha (Roghnaigh Seisiún i dtosach báire) GenericName[gl]=Entorno de desenvolvemento integrado (Escolla unha sesión coa que comezar) GenericName[hu]=Integrált fejlesztői környezet (először munkamenet felvétele) GenericName[it]=Ambiente di sviluppo integrato (Scegliere la sessione con cui iniziare) GenericName[kk]=Біріктірілген құрастыру ортасы (Бастайтын сеансты таңдап алу) GenericName[lt]=Integruota programavimo aplinka (pasirinkite seansą su kuriuo startuosite) GenericName[nb]=Integrert utviklingsmiljø (velg økt å starte med) GenericName[nds]=Programmsmeed (Söök en Törn ut, mit den Du starten wullt) GenericName[nl]=Geïntegreerde ontwikkelomgeving (pak een sessie om mee te beginnen) GenericName[pl]=Zintegrowane środowisko programistyczne (Wybór sesji do rozpoczęcia) GenericName[pt]=Ambiente de Desenvolvimento Integrado (Seleccionar a sessão com que iniciar) GenericName[pt_BR]=Ambiente Integrado de Desenvolvimento (selecione a sessão para início) GenericName[ru]=Интегрированная среда разработки (с выбором начального сеанса) GenericName[sk]=Integrované vývojové prostredie (zvoľte sedenie na spustenie) GenericName[sl]=Integrirano razvojno okolje (izberite sejo za začetek) GenericName[sv]=Integrerad utvecklingsmiljö (välj session att starta) GenericName[tr]=Tümleşik Geliştirme Ortamı (Başlamak için oturum seçin) GenericName[ug]=يۈرۈشلەشتۈرۈلگەن ئىجادىيەت مۇھىتى(Pick Session to start with) GenericName[uk]=Комплексне середовище розробки (виберіть сеанс, з якого слід розпочати роботу) GenericName[x-test]=xxIntegrated Development Environment (Pick Session to start with)xx GenericName[zh_CN]=集成开发环境(选择要启动的会话) GenericName[zh_TW]=整合開發環境(選擇要開始的工作階段) Categories=Qt;KDE;Development;IDE; +X-AppStream-Ignore=true diff --git a/kdevplatform/shell/mainwindow.cpp b/kdevplatform/shell/mainwindow.cpp index 6da872723c..b49e28173e 100644 --- a/kdevplatform/shell/mainwindow.cpp +++ b/kdevplatform/shell/mainwindow.cpp @@ -1,574 +1,576 @@ /* This file is part of the KDevelop project Copyright 2002 Falk Brettschneider Copyright 2003 John Firebaugh Copyright 2006 Adam Treat Copyright 2006, 2007 Alexander Dymo This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "mainwindow.h" #include "mainwindow_p.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include "shellextension.h" #include "partcontroller.h" #include "plugincontroller.h" #include "projectcontroller.h" #include "uicontroller.h" #include "documentcontroller.h" #include "workingsetcontroller.h" #include "sessioncontroller.h" #include "sourceformattercontroller.h" #include "areadisplay.h" #include "project.h" #include "debug.h" #include "uiconfig.h" #include "ktexteditorpluginintegration.h" #include #include #include #include #include #include #include #include using namespace KDevelop; namespace { QColor defaultColor(const QPalette& palette) { return palette.windowText().color(); } QColor colorForDocument(const QUrl& url, const QPalette& palette, const QColor& defaultColor) { auto project = Core::self()->projectController()->findProjectForUrl(url); if (!project) return defaultColor; return WidgetColorizer::colorForId(qHash(project->path()), palette); } } void MainWindow::applyMainWindowSettings(const KConfigGroup& config) { Q_D(MainWindow); if(!d->changingActiveView()) KXmlGuiWindow::applyMainWindowSettings(config); } void MainWindow::createGUI(KParts::Part* part) { - //TODO remove if-clause once KF5 >= 5.24 is required -#if KPARTS_VERSION_MINOR >= 24 Sublime::MainWindow::setWindowTitleHandling(false); Sublime::MainWindow::createGUI(part); -#else - Sublime::MainWindow::createGUI(part); - if (part) { - // Don't let the Part control the main window caption -- we take care of that - disconnect(part, SIGNAL(setWindowCaption(QString)), - this, SLOT(setCaption(QString))); - } -#endif } void MainWindow::initializeCorners() { const KConfigGroup cg = KSharedConfig::openConfig()->group( "UiSettings" ); const int bottomleft = cg.readEntry( "BottomLeftCornerOwner", 0 ); const int bottomright = cg.readEntry( "BottomRightCornerOwner", 0 ); qCDebug(SHELL) << "Bottom Left:" << bottomleft; qCDebug(SHELL) << "Bottom Right:" << bottomright; // 0 means vertical dock (left, right), 1 means horizontal dock( top, bottom ) if( bottomleft == 0 ) setCorner( Qt::BottomLeftCorner, Qt::LeftDockWidgetArea ); else if( bottomleft == 1 ) setCorner( Qt::BottomLeftCorner, Qt::BottomDockWidgetArea ); if( bottomright == 0 ) setCorner( Qt::BottomRightCorner, Qt::RightDockWidgetArea ); else if( bottomright == 1 ) setCorner( Qt::BottomRightCorner, Qt::BottomDockWidgetArea ); } MainWindow::MainWindow( Sublime::Controller *parent, Qt::WindowFlags flags ) : Sublime::MainWindow( parent, flags ) { QDBusConnection::sessionBus().registerObject( QStringLiteral("/kdevelop/MainWindow"), this, QDBusConnection::ExportScriptableSlots ); setAcceptDrops( true ); initializeCorners(); setObjectName( QStringLiteral("MainWindow") ); d_ptr = new MainWindowPrivate(this); Q_D(MainWindow); setStandardToolBarMenuEnabled( true ); d->setupActions(); if( !ShellExtension::getInstance()->xmlFile().isEmpty() ) { setXMLFile( ShellExtension::getInstance() ->xmlFile() ); } menuBar()->setCornerWidget(new AreaDisplay(this), Qt::TopRightCorner); } MainWindow::~ MainWindow() { if (memberList().count() == 1) { // We're closing down... Core::self()->shutdown(); } delete d_ptr; } KTextEditorIntegration::MainWindow *MainWindow::kateWrapper() const { Q_D(const MainWindow); return d->kateWrapper(); } void MainWindow::split(Qt::Orientation orientation) { Q_D(MainWindow); d->split(orientation); } void MainWindow::ensureVisible() { if (isMinimized()) { if (isMaximized()) { showMaximized(); } else { showNormal(); } } KWindowSystem::forceActiveWindow(winId()); } QAction* MainWindow::createCustomElement(QWidget* parent, int index, const QDomElement& element) { QAction* before = nullptr; if (index > 0 && index < parent->actions().count()) before = parent->actions().at(index); //KDevelop needs to ensure that separators defined as //are always shown in the menubar. For those, we create special disabled actions //instead of calling QMenuBar::addSeparator() because menubar separators are ignored if (element.tagName().toLower() == QLatin1String("separator") && element.attribute(QStringLiteral("style")) == QLatin1String("visible")) { if ( auto* bar = qobject_cast( parent ) ) { QAction *separatorAction = new QAction(QStringLiteral("|"), this); bar->insertAction( before, separatorAction ); separatorAction->setDisabled(true); return separatorAction; } } return KXMLGUIBuilder::createCustomElement(parent, index, element); } bool KDevelop::MainWindow::event( QEvent* ev ) { if ( ev->type() == QEvent::PaletteChange ) updateAllTabColors(); return Sublime::MainWindow::event(ev); } void MainWindow::dragEnterEvent( QDragEnterEvent* ev ) { const QMimeData* mimeData = ev->mimeData(); if (mimeData->hasUrls()) { ev->acceptProposedAction(); } else if (mimeData->hasText()) { // also take text which contains a URL const QUrl url = QUrl::fromUserInput(mimeData->text()); if (url.isValid()) { ev->acceptProposedAction(); } } } void MainWindow::dropEvent( QDropEvent* ev ) { Sublime::View* dropToView = viewForPosition(mapToGlobal(ev->pos())); if(dropToView) activateView(dropToView); QList urls; const QMimeData* mimeData = ev->mimeData(); if (mimeData->hasUrls()) { urls = mimeData->urls(); } else if (mimeData->hasText()) { const QUrl url = QUrl::fromUserInput(mimeData->text()); if (url.isValid()) { urls << url; } } bool eventUsed = false; if (urls.size() == 1) { eventUsed = Core::self()->projectControllerInternal()->fetchProjectFromUrl(urls.at(0), ProjectController::NoFetchFlags); } if (!eventUsed) { for(const auto& url : qAsConst(urls)) { Core::self()->documentController()->openDocument(url); } } ev->acceptProposedAction(); } void MainWindow::loadSettings() { qCDebug(SHELL) << "Loading Settings"; initializeCorners(); updateAllTabColors(); Sublime::MainWindow::loadSettings(); } void MainWindow::configureShortcuts() { ///Workaround for a problem with the actions: Always start the shortcut-configuration in the first mainwindow, then propagate the updated ///settings into the other windows // We need to bring up the shortcut dialog ourself instead of // Core::self()->uiControllerInternal()->mainWindows()[0]->guiFactory()->configureShortcuts(); // so we can connect to the saved() signal to propagate changes in the editor shortcuts KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this); const auto firstMainWindowClientsBefore = Core::self()->uiControllerInternal()->mainWindows()[0]->guiFactory()->clients(); for (KXMLGUIClient* client : firstMainWindowClientsBefore) { if(client && !client->xmlFile().isEmpty()) dlg.addCollection( client->actionCollection() ); } connect(&dlg, &KShortcutsDialog::saved, this, &MainWindow::shortcutsChanged); dlg.configure(true); QMap shortcuts; // querying again just in case something changed behind our back const auto firstMainWindowClientsAfter = Core::self()->uiControllerInternal()->mainWindows()[0]->guiFactory()->clients(); for (KXMLGUIClient* client : firstMainWindowClientsAfter) { const auto actions = client->actionCollection()->actions(); for (QAction* action : actions) { if(!action->objectName().isEmpty()) { shortcuts[action->objectName()] = action->shortcut(); } } } for(int a = 1; a < Core::self()->uiControllerInternal()->mainWindows().size(); ++a) { const auto clients = Core::self()->uiControllerInternal()->mainWindows()[a]->guiFactory()->clients(); for (KXMLGUIClient* client : clients) { const auto actions = client->actionCollection()->actions(); for (QAction* action : actions) { qCDebug(SHELL) << "transferring setting shortcut for" << action->objectName(); const auto shortcutIt = shortcuts.constFind(action->objectName()); if (shortcutIt != shortcuts.constEnd()) { action->setShortcut(*shortcutIt); } } } } } void MainWindow::shortcutsChanged() { KTextEditor::View *activeClient = Core::self()->documentController()->activeTextDocumentView(); if(!activeClient) return; const auto documents = Core::self()->documentController()->openDocuments(); for (IDocument* doc : documents) { KTextEditor::Document *textDocument = doc->textDocument(); if (textDocument) { const auto views = textDocument->views(); for (KTextEditor::View* client : views) { if (client != activeClient) { client->reloadXML(); } } } } } void MainWindow::initialize() { Q_D(MainWindow); KStandardAction::keyBindings(this, SLOT(configureShortcuts()), actionCollection()); setupGUI( KXmlGuiWindow::ToolBar | KXmlGuiWindow::Create | KXmlGuiWindow::Save ); Core::self()->partController()->addManagedTopLevelWidget(this); qCDebug(SHELL) << "Adding plugin-added connection"; connect( Core::self()->pluginController(), &IPluginController::pluginLoaded, d, &MainWindowPrivate::addPlugin); connect( Core::self()->pluginController(), &IPluginController::pluginUnloaded, d, &MainWindowPrivate::removePlugin); connect( Core::self()->partController(), &IPartController::activePartChanged, d, &MainWindowPrivate::activePartChanged); connect( this, &MainWindow::activeViewChanged, d, &MainWindowPrivate::changeActiveView); connect(Core::self()->sourceFormatterControllerInternal(), &SourceFormatterController::hasFormattersChanged, d, &MainWindowPrivate::updateSourceFormatterGuiClient); const auto plugins = Core::self()->pluginController()->loadedPlugins(); for (IPlugin* plugin : plugins) { d->addPlugin(plugin); } guiFactory()->addClient(Core::self()->sessionController()); if (Core::self()->sourceFormatterControllerInternal()->hasFormatters()) { guiFactory()->addClient(Core::self()->sourceFormatterControllerInternal()); } // Needed to re-plug the actions from the sessioncontroller as xmlguiclients don't // seem to remember which actions where plugged in. Core::self()->sessionController()->updateXmlGuiActionList(); d->setupGui(); qRegisterMetaType>(); //Queued so we process it with some delay, to make sure the rest of the UI has already adapted connect(Core::self()->documentController(), &IDocumentController::documentActivated, // Use a queued connection, because otherwise the view is not yet fully set up // but wrap the document in a smart pointer to guard against crashes when it // gets deleted in the meantime this, [this](IDocument *doc) { const auto textDocument = QPointer(doc->textDocument()); QMetaObject::invokeMethod(this, "documentActivated", Qt::QueuedConnection, Q_ARG(QPointer, textDocument)); }); connect(Core::self()->documentController(), &IDocumentController::documentClosed, this, &MainWindow::updateCaption, Qt::QueuedConnection); connect(Core::self()->documentController(), &IDocumentController::documentUrlChanged, this, &MainWindow::updateCaption, Qt::QueuedConnection); + connect(Core::self()->documentController(), &IDocumentController::documentStateChanged, this, &MainWindow::updateCaption, Qt::QueuedConnection); connect(Core::self()->sessionController()->activeSession(), &ISession::sessionUpdated, this, &MainWindow::updateCaption); connect(Core::self()->documentController(), &IDocumentController::documentOpened, this, &MainWindow::updateTabColor); connect(Core::self()->documentController(), &IDocumentController::documentUrlChanged, this, &MainWindow::updateTabColor); connect(this, &Sublime::MainWindow::viewAdded, this, &MainWindow::updateAllTabColors); connect(Core::self()->projectController(), &ProjectController::projectOpened, this, &MainWindow::updateAllTabColors, Qt::QueuedConnection); updateCaption(); } void MainWindow::cleanup() { } void MainWindow::setVisible( bool visible ) { KXmlGuiWindow::setVisible( visible ); emit finishedLoading(); } bool MainWindow::queryClose() { if (!Core::self()->documentControllerInternal()->saveAllDocumentsForWindow(this, IDocument::Default)) return false; return Sublime::MainWindow::queryClose(); } void MainWindow::documentActivated(const QPointer& textDocument) { Q_D(MainWindow); updateCaption(); // update active document connection disconnect(d->activeDocumentReadWriteConnection); if (textDocument) { d->activeDocumentReadWriteConnection = connect(textDocument, &KTextEditor::Document::readWriteChanged, this, &MainWindow::updateCaption); } } void MainWindow::updateCaption() { const auto activeSession = Core::self()->sessionController()->activeSession(); QString title = activeSession ? activeSession->description() : QString(); QString localFilePath; + bool isDocumentModified = false; if(area()->activeView()) { if(!title.isEmpty()) title += QLatin1String(" - [ "); Sublime::Document* doc = area()->activeView()->document(); auto* urlDoc = qobject_cast(doc); if(urlDoc) { if (urlDoc->url().isLocalFile()) { localFilePath = urlDoc->url().toLocalFile(); } title += Core::self()->projectController()->prettyFileName(urlDoc->url(), KDevelop::IProjectController::FormatPlain); } else title += doc->title(); - auto activeDocument = Core::self()->documentController()->activeDocument(); - if (activeDocument && activeDocument->textDocument() && !activeDocument->textDocument()->isReadWrite()) + auto iDoc = qobject_cast(doc); + if (iDoc && iDoc->textDocument() && !iDoc->textDocument()->isReadWrite()) { title += i18n(" (read only)"); + } - title += QLatin1String(" ]"); + title += QLatin1String(" [*]]"); // [*] is placeholder for modifed state, cmp. QWidget::windowModified + + isDocumentModified = iDoc && (iDoc->state() != IDocument::Clean); } - setWindowFilePath(localFilePath); + // Workaround for a bug observed on macOS with Qt 5.9.8 (TODO: test with newer Qt, report bug): + // Ensure to call setCaption() (thus implicitly setWindowTitle()) before + // setWindowModified() & setWindowFilePath(). + // Otherwise, if the state will change "modifed" from true to false as well change the title string, + // calling setWindowTitle() last results in the "modified" indicator==asterisk becoming part of the + // displayed window title somehow. + // Other platforms so far not known to be affected, any order of calls seems fine. setCaption(title); + setWindowModified(isDocumentModified); + setWindowFilePath(localFilePath); } void MainWindow::updateAllTabColors() { auto documentController = Core::self()->documentController(); if (!documentController) return; const auto defaultColor = ::defaultColor(palette()); if (UiConfig::colorizeByProject()) { QHash viewColors; const auto containers = this->containers(); for (auto* container : containers) { const auto views = container->views(); viewColors.reserve(views.size()); viewColors.clear(); for (auto view : views) { const auto urlDoc = qobject_cast(view->document()); if (urlDoc) { viewColors[view] = colorForDocument(urlDoc->url(), palette(), defaultColor); } } container->setTabColors(viewColors); } } else { const auto containers = this->containers(); for (auto* container : containers) { container->resetTabColors(defaultColor); } } } void MainWindow::updateTabColor(IDocument* doc) { if (!UiConfig::self()->colorizeByProject()) return; const auto color = colorForDocument(doc->url(), palette(), defaultColor(palette())); const auto containers = this->containers(); for (auto* container : containers) { const auto views = container->views(); for (auto* view : views) { const auto urlDoc = qobject_cast(view->document()); if (urlDoc && urlDoc->url() == doc->url()) { container->setTabColor(view, color); } } } } void MainWindow::registerStatus(QObject* status) { Q_D(MainWindow); d->registerStatus(status); } void MainWindow::initializeStatusBar() { Q_D(MainWindow); d->setupStatusBar(); } void MainWindow::showErrorMessage(const QString& message, int timeout) { Q_D(MainWindow); d->showErrorMessage(message, timeout); } void MainWindow::tabContextMenuRequested(Sublime::View* view, QMenu* menu) { Q_D(MainWindow); Sublime::MainWindow::tabContextMenuRequested(view, menu); d->tabContextMenuRequested(view, menu); } void MainWindow::tabToolTipRequested(Sublime::View* view, Sublime::Container* container, int tab) { Q_D(MainWindow); d->tabToolTipRequested(view, container, tab); } void MainWindow::dockBarContextMenuRequested(Qt::DockWidgetArea area, const QPoint& position) { Q_D(MainWindow); d->dockBarContextMenuRequested(area, position); } void MainWindow::newTabRequested() { Q_D(MainWindow); Sublime::MainWindow::newTabRequested(); d->fileNew(); } diff --git a/org.kde.kdevelop.appdata.xml b/org.kde.kdevelop.appdata.xml index fbbb215e8f..c854cecb03 100644 --- a/org.kde.kdevelop.appdata.xml +++ b/org.kde.kdevelop.appdata.xml @@ -1,150 +1,150 @@ org.kde.kdevelop.desktop CC0-1.0 GPL-2.0+ KDevelop مطوّرك KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop KDevelop xxKDevelopxx KDevelop KDevelop Featureful, plugin-extensible IDE for C/C++ and other programming languages بيئة تطوير متكاملة بمزايا عديدة ودعم للملحقات للغتي سي/سي++ ولغات البرمجة الأخرى És un IDE, extensible amb connectors, amb totes les característiques per a C/C++ i altres llenguatges de programació. És un IDE, extensible amb connectors, amb totes les característiques per a C/C++ i altres llenguatges de programació. Eine leistungsfähige integrierte Entwicklungsumgebung (IDE) für C/C++ und andere Programmiersprachen, die durch Module erweitert werden kann. Featureful, plugin-extensible IDE for C/C++ and other programming languages Entorno de desarrollo integrado para C/C++ y otros lenguajes de programación con múltiples funcionalidades y que se puede extender con complementos. Environnement de développement complet et extensible pour le C/C++ et d'autres langages de programmation. Potente ambiente de desenvolvemento integrado para C, C++ e outras linguaxes de programación. As súas funcionalidades poden estenderse mediante complementos Penuh fitur, IDE plugin yang dapat diekstensi C/C++ dan bahasa pemrograman lain IDE per C/C++ e altri linguaggi di programmazione completo ed estensibile C/C++ 및 기타 프로그래밍 언어를 위한 기능적이고 확장 가능한 IDE IDE voor C/C++ en andere programmeertalen, vol functies en uit te breiden met plug-ins. Jest to w pełni funkcjonalne, z możliwością rozszerzenia przy użyciu wtyczek, zintegrowane środowisko programistyczne dla C/C++ i innych języków programowania. IDE pleno de funcionalidades e modular para o C/C++ e outras linguagens de programação IDE repleto de funcionalidades e expansível através de plugins, para C/C++ e outras linguagens de programação. Plne funkčné, pluginmi rozšíriteľné IDE pre C/C++ a iné programovacie jazyky Zmogljivo integrirano razvojno okolje za C/C++ in druge programske jezike, ki je razširljivo z vstavki. Funktionsrik, integrerad utvecklingsmiljö för C/C++ och andra programspråk Tam özellikli, eklenti ile geliştirilebilir C/C++ ve diğer programlama dilleri için tümleşik geliştirme ortamı. Це повноцінне, розширюване за допомогою додатків комплексне середовище розробки мовами C/C++ та іншими мовами програмування. xxFeatureful, plugin-extensible IDE for C/C++ and other programming languagesxx 全功能,可扩展的支持 C/C++ 和其他语言的集成开发环境。

KDevelop is a Free and Open Source integrated development environment (IDE).

«مطوّرك» هي بيئة تطوير متكاملة (IDE) حرّة ومفتوحة المصدر.

El KDevelop és un entorn de desenvolupament integrat (IDE) lliure i de codi obert.

El KDevelop és un entorn de desenvolupament integrat (IDE) lliure i de codi obert.

KDevelop ist eine integrierte Entwicklungsumgebung (Frei und Open Source).

KDevelop is a Free and Open Source integrated development environment (IDE).

KDevelop es un entorno de desarrollo integrado (IDE) libre y de código abierto.

KDevelop est un environnement de développement intégré (IDE) libre et en open source.

KDevelop é un ambiente integrado de desenvolvemento (IDE) libre e de código aberto.

KDevelop adalah sebuah IDE (integrated development environment) lingkungan pengembangan terintegrasi yang Gratis dan Bebas Terbuka.

KDevelop è un ambiente di sviluppo integrato (IDE) libero e open source.

KDevelop은 자유 오픈 소스 통합 개발 환경(IDE)입니다.

KDevelop is een vrije geïntegreerde ontwikkelomgeving (IDE) binnen het open source principe.

KDevelop to darmowe i otwartoźródłowe zintegrowane środkowisko programistyczne (IDE).

O KDevelop é um ambiente de desenvolvimento integrado (IDE) livre e em código aberto.

Ambiente de Desenvolvimento Integrado (IDE) em Software Livre e Código Aberto.

KDevelop je slobodné a otvorené integrované vývojové prostredie (IDE).

KDevelop je prosto in odprtokodno integrirano razvojno okolje (IDE).

KDevelop är en fri integrerad utvecklingsmiljö (IDE) med öppen källkod för olika programvaruprojekt.

KDevelop Özgür ve Açık Kaynaklı tümleşik geliştirme ortamıdır (IDE).

KDevelop є вільним комплексним середовищем розробки (IDE) з відкритим кодом.

xxKDevelop is a Free and Open Source integrated development environment (IDE).xx

可用于您的不同软件项目的自由和开源的集成开发环境

It provides editing, navigation and debugging features for several programming languages, as well as integration with multiple build systems and version-control systems, using a plugin-based architecture.

توفّر البرمجيّة مزايا التّحرير والتّنقّل والتّنقيح لمختلف لغات البرمجة، إلى جانب التّكامل مع مختلف أنظمة البناء وأنظمة التّحكّم بالإصدارات، وذلك عبر البنية المعتمدة على الملحقات.

Proporciona característiques per a l'edició, navegació i depuració per a diversos llenguatges de programació, així com la integració amb múltiples sistemes de construcció i sistemes de control de versions, emprant una arquitectura basada en connectors.

Proporciona característiques per a l'edició, navegació i depuració per a diversos llenguatges de programació, així com la integració amb múltiples sistemes de construcció i sistemes de control de versions, emprant una arquitectura basada en connectors.

Funktionen zum Editieren, Navigieren und zur Fehlersuche für mehrere Programmiersprachen, dazu auch Integration von mehreren Build- und Versionskontrollsystemen auf der Basis einer modularen Architektur.

It provides editing, navigation and debugging features for several programming languages, as well as integration with multiple build systems and version-control systems, using a plugin-based architecture.

Proporciona funciones de edición, navegación y depuración para varios lenguajes de programación, además de integración con diversos sistemas de compilación y de control de versiones, usando una arquitectura basada en complementos.

Il fournit des fonctionnalités d'édition, navigation et débogage pour plusieurs langages de programmation, ainsi que l'intégration de multiples systèmes de compilation et de gestion de révision, en utilisant une architecture extensible.

Fornece funcionalidades de edición, navegación e depuración para varias linguaxes de programación, así como integración con varios sistemas de construción e sistemas de control de versións, usando unha arquitectura baseada en complementos.

Ini menyediakan fitur pengeditan, navigasi dan debugging untuk beberapa bahasa pemrograman, serta integrasi dengan sistem build multipel dan sistem kontrol versi, menggunakan arsitektur berbasis plugin.

Fornisce funzionalità di modifica, navigazione debug per vari linguaggi di programmazione, così come l'integrazione con vari sistemi di compilazione e di controllo versione, tramite l'uso di architettura basata sulle estensioni.

또한 플러그인 기반 아키텍처를 사용하여 여러 프로그래밍 언어에 대한 편집, 탐색 및 디버깅 기능을 제공하고 여러 빌드 시스템 및 버전 제어 시스템과의 통합도 제공합니다.

Het biedt functies voor bewerking, navigatie en debugging voor verschillende programmeertalen, evenals integratie met meerdere bouwsystemen en versiecontrole systemen, met gebruik van een op plug-ins gebaseerde architectuur.

Zapewnia możliwość edycji, poruszania się po projekcie i diagnozowania błędów dla kilku języków programistycznych, a także integrację z wieloma systemami budowania i zarządzania wersjami poprzez wbudowaną architekturę wtyczek.

Oferece capacidades de edição, navegação e depuração para diversas linguagens de programação, assim como a integração com diversos sistemas de compilação e de controlo de versões, usando uma arquitectura baseada em 'plugins'.

Oferece capacidades de edição, navegação e depuração para diversas linguagens de programação, assim como a integração com diversos sistemas de compilação e de controle de versões, usando uma arquitetura baseada em plugins.

Poskytuje funkcie editovania, navigácie a ladenia pre niektoré programovacie jazyky, ako aj integráciu s viacerými zostavovacími systémami a systémami na správu verzií pomocou pluginovej architektúry.

S pomočjo vstavkov omogoča urejanje, krmarjenje in razhroščevanje za številne programske jezike, hkrati pa ponuja podporo več sistemom za izgradnjo in nadzor različic.

Den tillhandahåller redigerings-, navigerings- och avlusningsfunktioner för flera olika programspråk, samt integrering med ett flertal byggsystem och versionskontrollsystem, med användning av en insticksbaserad arkitektur.

Bir çok programlama dili için düzenleme, gezinme ve hata ayıklama özellikleri sağlar, ayrıca bir çok inşa sistemi ve sürüm kontrol sistemi ile tümleşik olup eklenti-tabanlı mimari kullanır.

У програмі передбачено можливості з редагування, навігації та діагностики коду декількома мовами програмування, а також інтеграцію із декількома системами збирання коду та керування версіями. Використовується архітектура з додатками.

xxIt provides editing, navigation and debugging features for several programming languages, as well as integration with multiple build systems and version-control systems, using a plugin-based architecture.xx

它提供了多种编程语言的编辑、导航和调试功能,以及与多种构建系统和版本控制系统的集成,使用基于插件的体系结构。

KDevelop has parser backends for C, C++ and Javascript/QML, with further external plugins supporting e.g. PHP or Python.

لدى «مطوّرك» سندات تحليل للغات سي، وسي++، وجاڤاسكربت/QML كما وملحقات خارجيّة أخرى تدعم PHP أو پيثون.

El KDevelop disposa de dorsals d'analitzador per a C, C ++ i Javascript/QML, amb altres connectors externs que implementen, p. ex., PHP o Python.

El KDevelop disposa de dorsals d'analitzador per a C, C ++ i Javascript/QML, amb altres connectors externs que implementen, p. ex., PHP o Python.

KDevelop beinhaltet Parser-Module für C, C++ und Javascript/QML, weitere externe Module unterstützten zum Beispiel PHP oder Python.

KDevelop has parser backends for C, C++ and Javascript/QML, with further external plugins supporting e.g. PHP or Python.

KDevelop dispone de motores de análisis sintáctico para C, C++ y JavaScript/QML, además de complementos externos (por ejemplo, para PHP o para Python).

KDevelop intègre des parseurs pour le C, le C++ et Javascript/QML, avec des modules externes pour prendre en charge PHP, Python, etc.

KDevelop ten infraestruturas de análise para C, C++ e JavaScript/QML, con complementos externos adicionais que fornecen compatibilidade, por exemplo, con PHP e Python.

KDevelop memiliki pengurai backend untuk C, C++ dan Javascript/QML, dengan mendukung plugin eksternal lebih lanjut misal PHP atau Python.

KDevelop ha dei motori di analisi per C, C++ e JavaScript/QML, come ulteriori estensioni esterne che supportano, ad esempio, PHP o Python.

KDevelop에는 C, C++ 및 Javascript/QML에 대한 파서 백엔드가 있으며, PHP 또는 Python과 같은 추가 외부 플러그인이 지원됩니다.

KDevelop heef backends voor ontleden van C, C++ en Javascript/QML, met verdere externe plug-ins die bijv. PHP of Python ondersteunen.

KDevelop ma silniki do przetwarzania składni C, C++ oraz Javascript/QML, a także inne jak np. PHP lub Python dodawane przy użyciu zewnętrznych wtyczek.

O KDevelop tem infra-estruturas de processamento para C, C++ e Javascript/QML, com mais 'plugins' externos que suportam p.ex. PHP ou Python.

O KDevelop tem infraestruturas de processamento para C, C++ e Javascript/QML, com mais plugins externos que tem suporte a, por exemplo, PHP ou Python.

KDevelop má backendy parsera pre C, C++ a Javascript/QML, s ďalšími externými pluginmi podporujúcimi napr. PHP alebo Python.

KDevelop vsebuje razčlenjevalna zaledja za C, C++ in Javascript/QML, zunanji vstavki pa podpirajo tudi npr. PHP ali Python.

KDevelop har gränssnitt för tolkning av C, C++ och Javascript/QML, med ytterligare externa insticksprogram som stöder t.ex. PHP eller Python.

KDevelop C, C++ ve Javascript/QML için ayrıştırma arka uçlarına sahiptir, harici eklentilerle örn. PHP veya Python da desteklenir.

У KDevelop передбачено модулі обробки коду мовами C, C++ та Javascript/QML та додатки для розширення підтримки коду іншими мовами програмування, зокрема PHP і Python.

xxKDevelop has parser backends for C, C++ and Javascript/QML, with further external plugins supporting e.g. PHP or Python.xx

KDevelop 提供了 C、C++ 和 JavaScript/QML 的解析器后端,并通过插件提供 PHP 和 Python 等语言的支持。

https://kdevelop.org https://bugs.kde.org/enter_bug.cgi?format=guided&product=kdevelop https://docs.kde.org/index.php?application=kdevelop https://www.kde.org/community/donations/?app=kdevelop https://kde.org/images/screenshots/kdevelop.png KDE kdevelop - org.kde.kdevelop_ps.desktop + org.kde.kdevelop.desktop kdevelop Development IDE kfunk@kde.org
diff --git a/plugins/clang/util/clangutils.cpp b/plugins/clang/util/clangutils.cpp index e4ee4038ca..416f13798f 100644 --- a/plugins/clang/util/clangutils.cpp +++ b/plugins/clang/util/clangutils.cpp @@ -1,481 +1,485 @@ /* * Copyright 2014 Kevin Funk * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "clangutils.h" #include "../util/clangdebug.h" #include "../util/clangtypes.h" #include "../duchain/cursorkindtraits.h" #include "../duchain/documentfinderhelpers.h" #include #include #include #include #include #include #include #include using namespace KDevelop; CXCursor ClangUtils::getCXCursor(int line, int column, const CXTranslationUnit& unit, const CXFile& file) { if (!file) { clangDebug() << "getCXCursor couldn't find file: " << clang_getFileName(file); return clang_getNullCursor(); } CXSourceLocation location = clang_getLocation(unit, file, line + 1, column + 1); if (clang_equalLocations(clang_getNullLocation(), location)) { clangDebug() << "getCXCursor given invalid position " << line << ", " << column << " for file " << clang_getFileName(file); return clang_getNullCursor(); } return clang_getCursor(unit, location); } QVector ClangUtils::unsavedFiles() { QVector ret; const auto documents = ICore::self()->documentController()->openDocuments(); for (auto* document : documents) { auto textDocument = document->textDocument(); // TODO: Introduce a cache so we don't have to re-read all the open documents // which were not changed since the last run if (!textDocument || !textDocument->url().isLocalFile() || !DocumentFinderHelpers::mimeTypesList().contains(textDocument->mimeType())) { continue; } if (!textDocument->isModified()) { continue; } ret << UnsavedFile(textDocument->url().toLocalFile(), textDocument->textLines(textDocument->documentRange())); } return ret; } KTextEditor::Range ClangUtils::rangeForIncludePathSpec(const QString& line, const KTextEditor::Range& originalRange) { static const QRegularExpression pattern(QStringLiteral("^\\s*(#\\s*include|#\\s*import)")); if (!line.contains(pattern)) { return KTextEditor::Range::invalid(); } KTextEditor::Range range = originalRange; int pos = 0; char term_char = 0; for (; pos < line.size(); ++pos) { if (line[pos] == QLatin1Char('"') || line[pos] == QLatin1Char('<')) { term_char = line[pos] == QLatin1Char('"') ? '"' : '>'; range.setStart({ range.start().line(), ++pos }); break; } } for (; pos < line.size(); ++pos) { if (line[pos] == QLatin1Char('\\')) { ++pos; continue; } else if(line[pos] == QLatin1Char(term_char)) { range.setEnd({ range.start().line(), pos }); break; } } return range; } namespace { struct FunctionInfo { KTextEditor::Range range; QString fileName; CXTranslationUnit unit; QStringList stringParts; }; CXChildVisitResult paramVisitor(CXCursor cursor, CXCursor /*parent*/, CXClientData data) { //Ignore the type of the parameter CXCursorKind kind = clang_getCursorKind(cursor); if (kind == CXCursor_TypeRef || kind == CXCursor_TemplateRef || kind == CXCursor_NamespaceRef) { return CXChildVisit_Continue; } auto *info = static_cast(data); ClangRange range(clang_getCursorExtent(cursor)); CXFile file; clang_getFileLocation(clang_getCursorLocation(cursor),&file,nullptr,nullptr,nullptr); if (!file) { clangDebug() << "Couldn't find file associated with default parameter cursor!"; //We keep going, because getting an error because we accidentally duplicated //a default parameter is better than deleting a default parameter } QString fileName = ClangString(clang_getFileName(file)).toString(); //Clang doesn't make a distinction between the default arguments being in //the declaration or definition, and the default arguments don't have lexical //parents. So this range check is the only thing that really works. if ((info->fileName.isEmpty() || fileName == info->fileName) && info->range.contains(range.toRange())) { const ClangTokens tokens(info->unit, range.range()); info->stringParts.reserve(info->stringParts.size() + tokens.size()); for (CXToken token : tokens) { info->stringParts.append(ClangString(clang_getTokenSpelling(info->unit, token)).toString()); } } return CXChildVisit_Continue; } } QVector ClangUtils::getDefaultArguments(CXCursor cursor, DefaultArgumentsMode mode) { if (!CursorKindTraits::isFunction(clang_getCursorKind(cursor))) { return QVector(); } int numArgs = clang_Cursor_getNumArguments(cursor); QVector arguments(mode == FixedSize ? numArgs : 0); QString fileName; CXFile file; clang_getFileLocation(clang_getCursorLocation(cursor),&file,nullptr,nullptr,nullptr); if (!file) { clangDebug() << "Couldn't find file associated with default parameter cursor!"; //The empty string serves as a wildcard string, because it's better to //duplicate a default parameter than delete one } else { fileName = ClangString(clang_getFileName(file)).toString(); } FunctionInfo info{ClangRange(clang_getCursorExtent(cursor)).toRange(), fileName, clang_Cursor_getTranslationUnit(cursor), QStringList()}; for (int i = 0; i < numArgs; i++) { CXCursor arg = clang_Cursor_getArgument(cursor, i); info.stringParts.clear(); clang_visitChildren(arg, paramVisitor, &info); //Clang includes the equal sign sometimes, but not other times. if (!info.stringParts.isEmpty() && info.stringParts.first() == QLatin1String("=")) { info.stringParts.removeFirst(); } //Clang seems to include the , or ) at the end of the param, so delete that - if (!info.stringParts.isEmpty() && (info.stringParts.last() == QLatin1String(",") || info.stringParts.last() == QLatin1String(")"))) { + if (!info.stringParts.isEmpty() && + ((info.stringParts.last() == QLatin1String(",")) || + (info.stringParts.last() == QLatin1String(")") && + // assuming otherwise matching "(" & ")" tokens + info.stringParts.count(QStringLiteral("(")) != info.stringParts.count(QStringLiteral(")"))))) { info.stringParts.removeLast(); } const QString result = info.stringParts.join(QString()); if (mode == FixedSize) { arguments.replace(i, result); } else if (!result.isEmpty()) { arguments << result; } } return arguments; } bool ClangUtils::isScopeKind(CXCursorKind kind) { return kind == CXCursor_Namespace || kind == CXCursor_StructDecl || kind == CXCursor_UnionDecl || kind == CXCursor_ClassDecl || kind == CXCursor_ClassTemplate || kind == CXCursor_ClassTemplatePartialSpecialization; } QString ClangUtils::getScope(CXCursor cursor, CXCursor context) { QStringList scope; if (clang_Cursor_isNull(context)) { context = clang_getCursorLexicalParent(cursor); } context = clang_getCanonicalCursor(context); CXCursor search = clang_getCursorSemanticParent(cursor); while (isScopeKind(clang_getCursorKind(search)) && !clang_equalCursors(search, context)) { scope.prepend(ClangString(clang_getCursorDisplayName(search)).toString()); search = clang_getCursorSemanticParent(search); } return scope.join(QStringLiteral("::")); } QString ClangUtils::getCursorSignature(CXCursor cursor, const QString& scope, const QVector& defaultArgs) { CXCursorKind kind = clang_getCursorKind(cursor); //Get the return type QString ret; ret.reserve(128); QTextStream stream(&ret); if (kind != CXCursor_Constructor && kind != CXCursor_Destructor) { stream << ClangString(clang_getTypeSpelling(clang_getCursorResultType(cursor))).toString() << ' '; } //Build the function name, with scope and parameters if (!scope.isEmpty()) { stream << scope << "::"; } QString functionName = ClangString(clang_getCursorSpelling(cursor)).toString(); if (functionName.contains(QLatin1Char('<'))) { stream << functionName.left(functionName.indexOf(QLatin1Char('<'))); } else { stream << functionName; } //Add the parameters and such stream << '('; int numArgs ; QVector args; // SEE https://bugs.kde.org/show_bug.cgi?id=368544 // clang_Cursor_getNumArguments returns -1 for FunctionTemplate // clang checks if cursor's Decl is ObjCMethodDecl or FunctionDecl // CXCursor_FunctionTemplate is neither of them instead it has a FunctionTemplateDecl // HACK Get function template arguments by visiting children if (kind == CXCursor_FunctionTemplate) { clang_visitChildren(cursor, [] (CXCursor cursor, CXCursor /*parent*/, CXClientData data) { if (clang_getCursorKind(cursor) == CXCursor_ParmDecl) { (static_cast*>(data))->push_back(cursor); } return CXChildVisit_Continue; }, &args); numArgs = args.size(); } else { numArgs = clang_Cursor_getNumArguments(cursor); args.reserve(numArgs); for (int i = 0; i < numArgs; i++) { CXCursor arg = clang_Cursor_getArgument(cursor, i); args.push_back(arg); } } for (int i = 0; i < numArgs; i++) { CXCursor arg = args[i]; //Clang formats pointer types as "t *x" and reference types as "t &x", while //KDevelop formats them as "t* x" and "t& x". Make that adjustment. const QString type = ClangString(clang_getTypeSpelling(clang_getCursorType(arg))).toString(); if (type.endsWith(QLatin1String(" *")) || type.endsWith(QLatin1String(" &"))) { stream << type.left(type.length() - 2) << type.at(type.length() - 1); } else { stream << type; } const QString id = ClangString(clang_getCursorDisplayName(arg)).toString(); if (!id.isEmpty()) { stream << ' ' << id; } if (i < defaultArgs.count() && !defaultArgs.at(i).isEmpty()) { stream << " = " << defaultArgs.at(i); } if (i < numArgs - 1) { stream << ", "; } } if (clang_Cursor_isVariadic(cursor)) { if (numArgs > 0) { stream << ", "; } stream << "..."; } stream << ')'; if (clang_CXXMethod_isConst(cursor)) { stream << " const"; } return ret; } QStringList ClangUtils::templateArgumentTypes(CXCursor cursor) { CXType typeList = clang_getCursorType(cursor); int templateArgCount = clang_Type_getNumTemplateArguments(typeList); QStringList types; types.reserve(templateArgCount); for (int i = 0; i < templateArgCount; ++i) { ClangString clangString(clang_getTypeSpelling(clang_Type_getTemplateArgumentAsType(typeList, i))); types.append(clangString.toString()); } return types; } QByteArray ClangUtils::getRawContents(CXTranslationUnit unit, CXSourceRange range) { const auto rangeStart = clang_getRangeStart(range); const auto rangeEnd = clang_getRangeEnd(range); unsigned int start, end; clang_getFileLocation(rangeStart, nullptr, nullptr, nullptr, &start); clang_getFileLocation(rangeEnd, nullptr, nullptr, nullptr, &end); QByteArray result; const ClangTokens tokens(unit, range); for (CXToken token : tokens) { const auto location = ClangLocation(clang_getTokenLocation(unit, token)); unsigned int offset; clang_getFileLocation(location, nullptr, nullptr, nullptr, &offset); if (offset < start) // TODO: Sometimes hit, see bug 357585 return {}; const int fillCharacters = offset - start - result.size(); Q_ASSERT(fillCharacters >= 0); if (fillCharacters < 0) return {}; result.append(QByteArray(fillCharacters, ' ')); const auto spelling = clang_getTokenSpelling(unit, token); result.append(clang_getCString(spelling)); clang_disposeString(spelling); } // Clang always appends the full range of the last token, even if this exceeds the end of the requested range. // Fix this. result.chop(result.size() - (end - start)); return result; } bool ClangUtils::isExplicitlyDefaultedOrDeleted(CXCursor cursor) { if (clang_getCursorAvailability(cursor) == CXAvailability_NotAvailable) { return true; } #if CINDEX_VERSION_MINOR >= 34 if (clang_CXXMethod_isDefaulted(cursor)) { return true; } #else auto declCursor = clang_getCanonicalCursor(cursor); CXTranslationUnit tu = clang_Cursor_getTranslationUnit(declCursor); ClangTokens tokens(tu, clang_getCursorExtent(declCursor)); bool lastTokenWasDeleteOrDefault = false; for (auto it = tokens.rbegin(), end = tokens.rend(); it != end; ++it) { CXToken token = *it; auto kind = clang_getTokenKind(token); switch (kind) { case CXToken_Comment: break; case CXToken_Identifier: case CXToken_Literal: lastTokenWasDeleteOrDefault = false; break; case CXToken_Punctuation: { ClangString spelling(clang_getTokenSpelling(tu, token)); const char* spellingCStr = spelling.c_str(); if (strcmp(spellingCStr, ")") == 0) { // a closing parent means we have reached the end of the function parameter list // therefore this function can't be explicitly deleted/defaulted return false; } else if (strcmp(spellingCStr, "=") == 0) { if (lastTokenWasDeleteOrDefault) { return true; } #if CINDEX_VERSION_MINOR < 31 // HACK: on old clang versions, we don't get the default/delete // so there, assume the function is defaulted or deleted // when the last token is an equal sign if (it == tokens.rbegin()) { return true; } #endif } lastTokenWasDeleteOrDefault = false; break; } case CXToken_Keyword: { ClangString spelling(clang_getTokenSpelling(tu, token)); const char* spellingCStr = spelling.c_str(); if (strcmp(spellingCStr, "default") == 0 #if CINDEX_VERSION_MINOR < 31 || strcmp(spellingCStr, "delete") == 0 #endif ) { lastTokenWasDeleteOrDefault = true; } else { lastTokenWasDeleteOrDefault = false; } break; } } } #endif return false; } KDevelop::ClassFunctionFlags ClangUtils::specialAttributes(CXCursor cursor) { // check for our injected attributes to detect Qt signals and slots // see also the contents of wrappedQtHeaders/QtCore/qobjectdefs.h ClassFunctionFlags flags = {}; if (cursor.kind == CXCursor_CXXMethod) { clang_visitChildren(cursor, [] (CXCursor cursor, CXCursor /*parent*/, CXClientData data) -> CXChildVisitResult { auto& flags = *static_cast(data); switch (cursor.kind) { case CXCursor_AnnotateAttr: { ClangString attribute(clang_getCursorDisplayName(cursor)); if (attribute.c_str() == QByteArrayLiteral("qt_signal")) { flags |= FunctionSignalFlag; } else if (attribute.c_str() == QByteArrayLiteral("qt_slot")) { flags |= FunctionSlotFlag; } break; } case CXCursor_CXXFinalAttr: flags |= FinalFunctionFlag; break; default: break; } return CXChildVisit_Break; }, &flags); } return flags; } unsigned int ClangUtils::skipTopCommentBlock(CXTranslationUnit unit, CXFile file) { const auto fileRange = clang_getRange(clang_getLocation(unit, file, 1, 1), clang_getLocation(unit, file, std::numeric_limits::max(), 1)); const ClangTokens tokens (unit, fileRange); const auto nonCommentToken = std::find_if(tokens.begin(), tokens.end(), [&](CXToken token) { return clang_getTokenKind(token) != CXToken_Comment; }); // explicitly handle this case, otherwise we skip the preceding whitespace if (nonCommentToken == tokens.begin()) { return 1; } const auto location = (nonCommentToken != tokens.end()) ? clang_getTokenExtent(unit, *nonCommentToken) : fileRange; return KTextEditor::Cursor(ClangRange(location).end()).line() + 1; }