diff --git a/kdevplatform/language/duchain/navigation/usesnavigationcontext.cpp b/kdevplatform/language/duchain/navigation/usesnavigationcontext.cpp index 80c18c7c25..db9de72291 100644 --- a/kdevplatform/language/duchain/navigation/usesnavigationcontext.cpp +++ b/kdevplatform/language/duchain/navigation/usesnavigationcontext.cpp @@ -1,70 +1,71 @@ /* Copyright 2008 David Nolden This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 "usesnavigationcontext.h" #include "useswidget.h" #include #include #include #include using namespace KDevelop; UsesNavigationContext::UsesNavigationContext(IndexedDeclaration declaration, AbstractNavigationContext* previousContext) : AbstractNavigationContext(TopDUContextPointer(), previousContext) , m_declaration(declaration) { m_widget = new UsesWidget(m_declaration); } UsesNavigationContext::~UsesNavigationContext() { delete m_widget; } QString UsesNavigationContext::name() const { return QStringLiteral("Uses"); } QString UsesNavigationContext::html(bool shorten) { + Q_UNUSED(shorten); clear(); modifyHtml() += QLatin1String("

"); if (auto context = previousContext()) { modifyHtml() += navigationHighlight(i18n("Uses of ")); makeLink(context->name(), context->name(), NavigationAction(context)); } else { KDevelop::DUChainReadLocker lock(DUChain::lock()); if (Declaration* decl = m_declaration.data()) { makeLink(i18n("Uses of %1", decl->toString()), DeclarationPointer( decl), NavigationAction::NavigateDeclaration); } } modifyHtml() += QLatin1String("

"); return currentHtml(); } QWidget* UsesNavigationContext::widget() const { return m_widget; } diff --git a/plugins/clang/duchain/macronavigationcontext.cpp b/plugins/clang/duchain/macronavigationcontext.cpp index 6c95db123f..5ddd418daf 100644 --- a/plugins/clang/duchain/macronavigationcontext.cpp +++ b/plugins/clang/duchain/macronavigationcontext.cpp @@ -1,94 +1,95 @@ /* Copyright 2007 David Nolden Copyright 2014 Kevin Funk This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 "macronavigationcontext.h" #include "util/clangdebug.h" #include "util/clangutils.h" #include #include using namespace KDevelop; MacroNavigationContext::MacroNavigationContext(const MacroDefinition::Ptr& macro, const KDevelop::DocumentCursor& /* expansionLocation */) : m_macro(macro) { } MacroNavigationContext::~MacroNavigationContext() { } QString MacroNavigationContext::name() const { return m_macro->identifier().toString(); } QString MacroNavigationContext::html(bool shorten) { + Q_UNUSED(shorten); clear(); modifyHtml() += QLatin1String("

"); QStringList parameterList; parameterList.reserve(m_macro->parametersSize()); FOREACH_FUNCTION(const auto& parameter, m_macro->parameters) { parameterList << parameter.str(); } const QString parameters = (!parameterList.isEmpty() ? QStringLiteral("(%1)").arg(parameterList.join(QStringLiteral(", "))) : QString()); const QUrl url = m_macro->url().toUrl(); const QString path = url.toLocalFile(); KTextEditor::Cursor cursor(m_macro->rangeInCurrentRevision().start()); NavigationAction action(url, cursor); modifyHtml() += i18nc("%1: macro type, i.e.: 'Function macro' or just 'Macro'" "%2: the macro name and arguments", "%1: %2", (m_macro->isFunctionLike() ? i18n("Function macro") : i18n("Macro")), importantHighlight(name()) + parameters); modifyHtml() += QStringLiteral("
"); modifyHtml() += i18nc("%1: the link to the definition", "Defined in: %1", createLink(QStringLiteral("%1 :%2").arg(url.fileName()).arg(cursor.line()+1), path, action)); modifyHtml() += QStringLiteral(" "); //The action name _must_ stay "show_uses", since that is also used from outside makeLink(i18n("Show uses"), QStringLiteral("show_uses"), NavigationAction(m_macro.dynamicCast(), NavigationAction::NavigateUses)); auto code = m_macro->definition().str(); modifyHtml() += QLatin1String("

") + i18n("Body: "); modifyHtml() += QLatin1String("") + code.toHtmlEscaped().replace(QLatin1Char('\n'), QStringLiteral("
")) + QLatin1String("
"); modifyHtml() += QStringLiteral("

"); modifyHtml() += QLatin1String("

"); return currentHtml(); } QString MacroNavigationContext::retrievePreprocessedBody(const DocumentCursor& /*expansionLocation*/) const { const TopDUContext* topContext = m_macro->topContext(); if (!topContext) { return QString(); } // TODO: Implement me. Still not exactly sure what do to here... return QString(); } diff --git a/plugins/custom-buildsystem/custombuildsystemplugin.cpp b/plugins/custom-buildsystem/custombuildsystemplugin.cpp index 695372dbab..323d55f633 100644 --- a/plugins/custom-buildsystem/custombuildsystemplugin.cpp +++ b/plugins/custom-buildsystem/custombuildsystemplugin.cpp @@ -1,203 +1,204 @@ /************************************************************************ * KDevelop4 Custom Buildsystem Support * * * * Copyright 2010 Andreas Pakulat * * * * 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 or version 3 of the License, or * * (at your option) any later version. * * * * 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 "custombuildsystemplugin.h" #include #include #include #include #include "configconstants.h" #include "kcm_custombuildsystem.h" #include "custombuildjob.h" using KDevelop::ProjectTargetItem; using KDevelop::ProjectFolderItem; using KDevelop::ProjectBuildFolderItem; using KDevelop::ProjectBaseItem; using KDevelop::ProjectFileItem; using KDevelop::IPlugin; using KDevelop::ICore; using KDevelop::IOutputView; using KDevelop::IProjectFileManager; using KDevelop::IProjectBuilder; using KDevelop::IProject; using KDevelop::Path; K_PLUGIN_FACTORY_WITH_JSON(CustomBuildSystemFactory, "kdevcustombuildsystem.json", registerPlugin(); ) CustomBuildSystem::CustomBuildSystem( QObject *parent, const QVariantList & ) : AbstractFileManagerPlugin( QStringLiteral("kdevcustombuildsystem"), parent ) { } CustomBuildSystem::~CustomBuildSystem() { } bool CustomBuildSystem::addFilesToTarget( const QList&, ProjectTargetItem* ) { return false; } bool CustomBuildSystem::hasBuildInfo( ProjectBaseItem* ) const { return false; } KJob* CustomBuildSystem::build( ProjectBaseItem* dom ) { return new CustomBuildJob( this, dom, CustomBuildSystemTool::Build ); } Path CustomBuildSystem::buildDirectory( ProjectBaseItem* item ) const { Path p; if( item->folder() ) { p = item->path(); } else { ProjectBaseItem* parent = item; while( !parent->folder() ) { parent = parent->parent(); } p = parent->path(); } const QString relative = item->project()->path().relativePath(p); KConfigGroup grp = configuration( item->project() ); if(!grp.isValid()) { return Path(); } Path builddir(grp.readEntry(ConfigConstants::buildDirKey(), QUrl())); if(!builddir.isValid() ) // set builddir to default if project contains a buildDirKey that does not have a value { builddir = item->project()->path(); } builddir.addPath( relative ); return builddir; } IProjectBuilder* CustomBuildSystem::builder() const { return const_cast(dynamic_cast(this)); } KJob* CustomBuildSystem::clean( ProjectBaseItem* dom ) { return new CustomBuildJob( this, dom, CustomBuildSystemTool::Clean ); } KJob* CustomBuildSystem::configure( IProject* project ) { return new CustomBuildJob( this, project->projectItem(), CustomBuildSystemTool::Configure ); } ProjectTargetItem* CustomBuildSystem::createTarget( const QString&, ProjectFolderItem* ) { return nullptr; } QHash CustomBuildSystem::defines( ProjectBaseItem* ) const { return {}; } IProjectFileManager::Features CustomBuildSystem::features() const { return IProjectFileManager::Files | IProjectFileManager::Folders; } ProjectFolderItem* CustomBuildSystem::createFolderItem( IProject* project, const Path& path, ProjectBaseItem* parent ) { return new ProjectBuildFolderItem( project, path, parent ); } Path::List CustomBuildSystem::includeDirectories( ProjectBaseItem* ) const { return {}; } Path::List CustomBuildSystem::frameworkDirectories( ProjectBaseItem* ) const { return {}; } QString CustomBuildSystem::extraArguments(KDevelop::ProjectBaseItem*) const { return {}; } KJob* CustomBuildSystem::install( KDevelop::ProjectBaseItem* item, const QUrl &installPrefix ) { auto job = new CustomBuildJob( this, item, CustomBuildSystemTool::Install ); job->setInstallPrefix(installPrefix); return job; } KJob* CustomBuildSystem::prune( IProject* project ) { return new CustomBuildJob( this, project->projectItem(), CustomBuildSystemTool::Prune ); } bool CustomBuildSystem::removeFilesFromTargets( const QList& ) { return false; } bool CustomBuildSystem::removeTarget( ProjectTargetItem* ) { return false; } QList CustomBuildSystem::targets( ProjectFolderItem* ) const { return QList(); } KConfigGroup CustomBuildSystem::configuration( IProject* project ) const { KConfigGroup grp = project->projectConfiguration()->group(ConfigConstants::customBuildSystemGroup()); if (grp.isValid() && grp.hasKey(ConfigConstants::currentConfigKey())) return grp.group(grp.readEntry(ConfigConstants::currentConfigKey())); else return KConfigGroup(); } int CustomBuildSystem::perProjectConfigPages() const { return 1; } KDevelop::ConfigPage* CustomBuildSystem::perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options, QWidget* parent) { if (number == 0) { return new CustomBuildSystemKCModule(this, options, parent); } return nullptr; } KDevelop::Path CustomBuildSystem::compiler(KDevelop::ProjectTargetItem* item) const { + Q_UNUSED(item); return {}; } #include "custombuildsystemplugin.moc" diff --git a/plugins/custommake/custommakemanager.cpp b/plugins/custommake/custommakemanager.cpp index 7eeed57a0b..f0a04778d3 100644 --- a/plugins/custommake/custommakemanager.cpp +++ b/plugins/custommake/custommakemanager.cpp @@ -1,332 +1,333 @@ /* KDevelop Custom Makefile Support * * Copyright 2007 Dukju Ahn * Copyright 2011 Milian Wolff * * 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) any later version. */ #include "custommakemanager.h" #include "custommakemodelitems.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; class CustomMakeProvider : public IDefinesAndIncludesManager::BackgroundProvider { public: explicit CustomMakeProvider(CustomMakeManager* manager) : m_customMakeManager(manager) , m_resolver(new MakeFileResolver()) {} // NOTE: Fixes build failures for GCC versions <4.8. // cf. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53613 ~CustomMakeProvider() Q_DECL_NOEXCEPT override; QHash< QString, QString > definesInBackground(const QString&) const override { return {}; } Path::List resolvePathInBackground(const QString& path, const bool isFrameworks) const { { QReadLocker lock(&m_lock); bool inProject = std::any_of(m_customMakeManager->m_projectPaths.constBegin(), m_customMakeManager->m_projectPaths.constEnd(), [&path](const QString& projectPath) { return path.startsWith(projectPath); } ); if (!inProject) { return {}; } } if (isFrameworks) { return m_resolver->resolveIncludePath(path).frameworkDirectories; } else { return m_resolver->resolveIncludePath(path).paths; } } Path::List includesInBackground(const QString& path) const override { return resolvePathInBackground(path, false); } Path::List frameworkDirectoriesInBackground(const QString& path) const override { return resolvePathInBackground(path, true); } IDefinesAndIncludesManager::Type type() const override { return IDefinesAndIncludesManager::ProjectSpecific; } CustomMakeManager* m_customMakeManager; QScopedPointer m_resolver; mutable QReadWriteLock m_lock; }; // NOTE: Fixes build failures for GCC versions <4.8. // See above. CustomMakeProvider::~CustomMakeProvider() Q_DECL_NOEXCEPT {} K_PLUGIN_FACTORY_WITH_JSON(CustomMakeSupportFactory, "kdevcustommakemanager.json", registerPlugin(); ) CustomMakeManager::CustomMakeManager( QObject *parent, const QVariantList& args ) : KDevelop::AbstractFileManagerPlugin( QStringLiteral("kdevcustommakemanager"), parent ) , m_provider(new CustomMakeProvider(this)) { Q_UNUSED(args) setXMLFile( QStringLiteral("kdevcustommakemanager.rc") ); // TODO use CustomMakeBuilder IPlugin* i = core()->pluginController()->pluginForExtension( QStringLiteral("org.kdevelop.IMakeBuilder") ); Q_ASSERT(i); m_builder = i->extension(); Q_ASSERT(m_builder); connect(this, &CustomMakeManager::reloadedFileItem, this, &CustomMakeManager::reloadMakefile); connect(ICore::self()->projectController(), &IProjectController::projectClosing, this, &CustomMakeManager::projectClosing); IDefinesAndIncludesManager::manager()->registerBackgroundProvider(m_provider.data()); } CustomMakeManager::~CustomMakeManager() { } IProjectBuilder* CustomMakeManager::builder() const { Q_ASSERT(m_builder); return m_builder; } Path::List CustomMakeManager::includeDirectories(KDevelop::ProjectBaseItem*) const { return Path::List(); } Path::List CustomMakeManager::frameworkDirectories(KDevelop::ProjectBaseItem*) const { return Path::List(); } QHash CustomMakeManager::defines(KDevelop::ProjectBaseItem*) const { return QHash(); } QString CustomMakeManager::extraArguments(KDevelop::ProjectBaseItem*) const { return {}; } ProjectTargetItem* CustomMakeManager::createTarget(const QString& target, KDevelop::ProjectFolderItem *parent) { Q_UNUSED(target) Q_UNUSED(parent) return nullptr; } bool CustomMakeManager::addFilesToTarget(const QList< ProjectFileItem* > &files, ProjectTargetItem* parent) { Q_UNUSED( files ) Q_UNUSED( parent ) return false; } bool CustomMakeManager::removeTarget(KDevelop::ProjectTargetItem *target) { Q_UNUSED( target ) return false; } bool CustomMakeManager::removeFilesFromTargets(const QList< ProjectFileItem* > &targetFiles) { Q_UNUSED( targetFiles ) return false; } bool CustomMakeManager::hasBuildInfo(KDevelop::ProjectBaseItem* item) const { Q_UNUSED(item); return false; } Path CustomMakeManager::buildDirectory(KDevelop::ProjectBaseItem* item) const { auto *fi=dynamic_cast(item); for(; !fi && item; ) { item=item->parent(); fi=dynamic_cast(item); } if(!fi) { return item->project()->path(); } return fi->path(); } QList CustomMakeManager::targets(KDevelop::ProjectFolderItem*) const { QList ret; return ret; } static bool isMakefile(const QString& fileName) { return ( fileName == QLatin1String("Makefile") || fileName == QLatin1String("makefile") || fileName == QLatin1String("GNUmakefile") || fileName == QLatin1String("BSDmakefile") ); } void CustomMakeManager::createTargetItems(IProject* project, const Path& path, ProjectBaseItem* parent) { Q_ASSERT(isMakefile(path.lastPathSegment())); foreach(const QString& target, parseCustomMakeFile( path )) { if (!isValid(Path(parent->path(), target), false, project)) { continue; } new CustomMakeTargetItem( project, target, parent ); } } ProjectFileItem* CustomMakeManager::createFileItem(IProject* project, const Path& path, ProjectBaseItem* parent) { auto* item = new ProjectFileItem(project, path, parent); if (isMakefile(path.lastPathSegment())){ createTargetItems(project, path, parent); } return item; } void CustomMakeManager::reloadMakefile(ProjectFileItem* file) { if( !isMakefile(file->path().lastPathSegment())){ return; } ProjectBaseItem* parent = file->parent(); // remove the items that are Makefile targets foreach(ProjectBaseItem* item, parent->children()){ if (item->target()){ delete item; } } // Recreate the targets. createTargetItems(parent->project(), file->path(), parent); } ProjectFolderItem* CustomMakeManager::createFolderItem(IProject* project, const Path& path, ProjectBaseItem* parent) { // TODO more faster algorithm. should determine whether this directory // contains makefile or not. return new KDevelop::ProjectBuildFolderItem( project, path, parent ); } KDevelop::ProjectFolderItem* CustomMakeManager::import(KDevelop::IProject *project) { if( project->path().isRemote() ) { //FIXME turn this into a real warning qCWarning(CUSTOMMAKE) << project->path() << "not a local file. Custom make support doesn't handle remote projects"; return nullptr; } { QWriteLocker lock(&m_provider->m_lock); m_projectPaths.insert(project->path().path()); } return AbstractFileManagerPlugin::import( project ); } ///////////////////////////////////////////////////////////////////////////// // private slots ///TODO: move to background thread, probably best would be to use a proper ParseJob QStringList CustomMakeManager::parseCustomMakeFile( const Path &makefile ) { if( !makefile.isValid() ) return QStringList(); QStringList ret; // the list of targets QFile f( makefile.toLocalFile() ); if ( !f.open( QIODevice::ReadOnly | QIODevice::Text ) ) { qCDebug(CUSTOMMAKE) << "could not open" << makefile; return ret; } QRegExp targetRe(QStringLiteral("^ *([^\\t$.#]\\S+) *:?:(?!=).*$")); targetRe.setMinimal( true ); QString str; QTextStream stream( &f ); while ( !stream.atEnd() ) { str = stream.readLine(); if ( targetRe.indexIn( str ) != -1 ) { QString tmpTarget = targetRe.cap( 1 ).simplified(); if ( ! ret.contains( tmpTarget ) ) ret.append( tmpTarget ); } } f.close(); return ret; } void CustomMakeManager::projectClosing(IProject* project) { QWriteLocker lock(&m_provider->m_lock); m_projectPaths.remove(project->path().path()); } void CustomMakeManager::unload() { IDefinesAndIncludesManager::manager()->unregisterBackgroundProvider(m_provider.data()); } KDevelop::Path CustomMakeManager::compiler(KDevelop::ProjectTargetItem* item) const { + Q_UNUSED(item); return {}; } #include "custommakemanager.moc" diff --git a/plugins/qmakemanager/qmakemanager.cpp b/plugins/qmakemanager/qmakemanager.cpp index bc3eff38f0..ecfda0d189 100644 --- a/plugins/qmakemanager/qmakemanager.cpp +++ b/plugins/qmakemanager/qmakemanager.cpp @@ -1,518 +1,519 @@ /* KDevelop QMake Support * * Copyright 2006 Andreas Pakulat * * 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) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "qmakemanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "qmakemodelitems.h" #include "qmakeprojectfile.h" #include "qmakecache.h" #include "qmakemkspecs.h" #include "qmakejob.h" #include "qmakebuilddirchooserdialog.h" #include "qmakeconfig.h" #include "qmakeutils.h" #include using namespace KDevelop; // BEGIN Helpers QMakeFolderItem* findQMakeFolderParent(ProjectBaseItem* item) { QMakeFolderItem* p = nullptr; while (!p && item) { p = dynamic_cast(item); item = item->parent(); } return p; } // END Helpers K_PLUGIN_FACTORY_WITH_JSON(QMakeSupportFactory, "kdevqmakemanager.json", registerPlugin();) QMakeProjectManager::QMakeProjectManager(QObject* parent, const QVariantList&) : AbstractFileManagerPlugin(QStringLiteral("kdevqmakemanager"), parent) , IBuildSystemManager() { IPlugin* i = core()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IQMakeBuilder")); Q_ASSERT(i); m_builder = i->extension(); Q_ASSERT(m_builder); connect(this, SIGNAL(folderAdded(KDevelop::ProjectFolderItem*)), this, SLOT(slotFolderAdded(KDevelop::ProjectFolderItem*))); m_runQMake = new QAction(QIcon::fromTheme(QStringLiteral("qtlogo")), i18n("Run QMake"), this); connect(m_runQMake, &QAction::triggered, this, &QMakeProjectManager::slotRunQMake); } QMakeProjectManager::~QMakeProjectManager() { } IProjectFileManager::Features QMakeProjectManager::features() const { return Features(Folders | Targets | Files); } bool QMakeProjectManager::isValid(const Path& path, const bool isFolder, IProject* project) const { if (!isFolder && path.lastPathSegment().startsWith(QLatin1String("Makefile"))) { return false; } return AbstractFileManagerPlugin::isValid(path, isFolder, project); } Path QMakeProjectManager::buildDirectory(ProjectBaseItem* item) const { /// TODO: support includes by some other parent or sibling in a different file-tree-branch QMakeFolderItem* qmakeItem = findQMakeFolderParent(item); Path dir; if (qmakeItem) { if (!qmakeItem->parent()) { // build root item dir = QMakeConfig::buildDirFromSrc(qmakeItem->project(), qmakeItem->path()); } else { // build sub-item foreach (QMakeProjectFile* pro, qmakeItem->projectFiles()) { if (QDir(pro->absoluteDir()) == QFileInfo(qmakeItem->path().toUrl().toLocalFile() + QLatin1Char('/')).absoluteDir() || pro->hasSubProject(qmakeItem->path().toUrl().toLocalFile())) { // get path from project root and it to buildDir dir = QMakeConfig::buildDirFromSrc(qmakeItem->project(), Path(pro->absoluteDir())); break; } } } } qCDebug(KDEV_QMAKE) << "build dir for" << item->text() << item->path() << "is:" << dir; return dir; } ProjectFolderItem* QMakeProjectManager::createFolderItem(IProject* project, const Path& path, ProjectBaseItem* parent) { if (!parent) { return projectRootItem(project, path); } else if (ProjectFolderItem* buildFolder = buildFolderItem(project, path, parent)) { // child folder in a qmake folder return buildFolder; } else { return AbstractFileManagerPlugin::createFolderItem(project, path, parent); } } ProjectFolderItem* QMakeProjectManager::projectRootItem(IProject* project, const Path& path) { QDir dir(path.toLocalFile()); auto item = new QMakeFolderItem(project, path); QHash qmvars = QMakeUtils::queryQMake(project); const QString mkSpecFile = QMakeConfig::findBasicMkSpec(qmvars); Q_ASSERT(!mkSpecFile.isEmpty()); QMakeMkSpecs* mkspecs = new QMakeMkSpecs(mkSpecFile, qmvars); mkspecs->setProject(project); mkspecs->read(); QMakeCache* cache = findQMakeCache(project); if (cache) { cache->setMkSpecs(mkspecs); cache->read(); } QStringList projectfiles = dir.entryList(QStringList() << QStringLiteral("*.pro")); for (const auto& projectfile : projectfiles) { Path proPath(path, projectfile); /// TODO: use Path in QMakeProjectFile QMakeProjectFile* scope = new QMakeProjectFile(proPath.toLocalFile()); scope->setProject(project); scope->setMkSpecs(mkspecs); if (cache) { scope->setQMakeCache(cache); } scope->read(); qCDebug(KDEV_QMAKE) << "top-level scope with variables:" << scope->variables(); item->addProjectFile(scope); } return item; } ProjectFolderItem* QMakeProjectManager::buildFolderItem(IProject* project, const Path& path, ProjectBaseItem* parent) { // find .pro or .pri files in dir QDir dir(path.toLocalFile()); const QStringList projectFiles = dir.entryList(QStringList{QStringLiteral("*.pro"), QStringLiteral("*.pri")}, QDir::Files); if (projectFiles.isEmpty()) { return nullptr; } auto folderItem = new QMakeFolderItem(project, path, parent); // TODO: included by not-parent file (in a nother file-tree-branch). QMakeFolderItem* qmakeParent = findQMakeFolderParent(parent); if (!qmakeParent) { // happens for bad qmake configurations return nullptr; } for (const QString& file : projectFiles) { const QString absFile = dir.absoluteFilePath(file); // TODO: multiple includes by different .pro's QMakeProjectFile* parentPro = nullptr; foreach (QMakeProjectFile* p, qmakeParent->projectFiles()) { if (p->hasSubProject(absFile)) { parentPro = p; break; } } if (!parentPro && file.endsWith(QLatin1String(".pri"))) { continue; } qCDebug(KDEV_QMAKE) << "add project file:" << absFile; if (parentPro) { qCDebug(KDEV_QMAKE) << "parent:" << parentPro->absoluteFile(); } else { qCDebug(KDEV_QMAKE) << "no parent, assume project root"; } auto qmscope = new QMakeProjectFile(absFile); qmscope->setProject(project); const QFileInfo info(absFile); const QDir d = info.dir(); /// TODO: cleanup if (parentPro) { // subdir if (QMakeCache* cache = findQMakeCache(project, Path(d.canonicalPath()))) { cache->setMkSpecs(parentPro->mkSpecs()); cache->read(); qmscope->setQMakeCache(cache); } else { qmscope->setQMakeCache(parentPro->qmakeCache()); } qmscope->setMkSpecs(parentPro->mkSpecs()); } else { // new project auto* root = dynamic_cast(project->projectItem()); Q_ASSERT(root); qmscope->setMkSpecs(root->projectFiles().first()->mkSpecs()); if (root->projectFiles().first()->qmakeCache()) { qmscope->setQMakeCache(root->projectFiles().first()->qmakeCache()); } } if (qmscope->read()) { // TODO: only on read? folderItem->addProjectFile(qmscope); } else { delete qmscope; return nullptr; } } return folderItem; } void QMakeProjectManager::slotFolderAdded(ProjectFolderItem* folder) { auto* qmakeParent = dynamic_cast(folder); if (!qmakeParent) { return; } qCDebug(KDEV_QMAKE) << "adding targets for" << folder->path(); foreach (QMakeProjectFile* pro, qmakeParent->projectFiles()) { foreach (const QString& s, pro->targets()) { if (!isValid(Path(folder->path(), s), false, folder->project())) { continue; } qCDebug(KDEV_QMAKE) << "adding target:" << s; Q_ASSERT(!s.isEmpty()); auto target = new QMakeTargetItem(pro, folder->project(), s, folder); foreach (const QString& path, pro->filesForTarget(s)) { new ProjectFileItem(folder->project(), Path(path), target); /// TODO: signal? } } } } ProjectFolderItem* QMakeProjectManager::import(IProject* project) { const Path dirName = project->path(); if (dirName.isRemote()) { // FIXME turn this into a real warning qCWarning(KDEV_QMAKE) << "not a local file. QMake support doesn't handle remote projects"; return nullptr; } QMakeUtils::checkForNeedingConfigure(project); ProjectFolderItem* ret = AbstractFileManagerPlugin::import(project); connect(projectWatcher(project), &KDirWatch::dirty, this, &QMakeProjectManager::slotDirty); return ret; } void QMakeProjectManager::slotDirty(const QString& path) { if (!path.endsWith(QLatin1String(".pro")) && !path.endsWith(QLatin1String(".pri"))) { return; } QFileInfo info(path); if (!info.isFile()) { return; } const QUrl url = QUrl::fromLocalFile(path); if (!isValid(Path(url), false, nullptr)) { return; } IProject* project = ICore::self()->projectController()->findProjectForUrl(url); if (!project) { // this can happen when we create/remove lots of files in a // sub dir of a project - ignore such cases for now return; } bool finished = false; foreach (ProjectFolderItem* folder, project->foldersForPath(IndexedString(KIO::upUrl(url)))) { if (auto* qmakeFolder = dynamic_cast(folder)) { foreach (QMakeProjectFile* pro, qmakeFolder->projectFiles()) { if (pro->absoluteFile() == path) { // TODO: children // TODO: cache added qCDebug(KDEV_QMAKE) << "reloading" << pro << path; pro->read(); } } finished = true; } else if (ProjectFolderItem* newFolder = buildFolderItem(project, folder->path(), folder->parent())) { qCDebug(KDEV_QMAKE) << "changing from normal folder to qmake project folder:" << folder->path().toUrl(); // .pro / .pri file did not exist before while (folder->rowCount()) { newFolder->appendRow(folder->takeRow(0)); } folder->parent()->removeRow(folder->row()); folder = newFolder; finished = true; } if (finished) { // remove existing targets and readd them for (int i = 0; i < folder->rowCount(); ++i) { if (folder->child(i)->target()) { folder->removeRow(i); } } /// TODO: put into it's own function once we add more stuff to that slot slotFolderAdded(folder); break; } } } QList QMakeProjectManager::targets(ProjectFolderItem* item) const { Q_UNUSED(item) return QList(); } IProjectBuilder* QMakeProjectManager::builder() const { Q_ASSERT(m_builder); return m_builder; } Path::List QMakeProjectManager::collectDirectories(ProjectBaseItem* item, const bool collectIncludes) const { Path::List list; QMakeFolderItem* folder = findQMakeFolderParent(item); if (folder) { foreach (QMakeProjectFile* pro, folder->projectFiles()) { if (pro->files().contains(item->path().toLocalFile())) { const QStringList directories = collectIncludes ? pro->includeDirectories() : pro->frameworkDirectories(); for (const QString& dir : directories) { Path path(dir); if (!list.contains(path)) { list << path; } } } } if (list.isEmpty()) { // fallback for new files, use all possible include dirs foreach (QMakeProjectFile* pro, folder->projectFiles()) { const QStringList directories = collectIncludes ? pro->includeDirectories() : pro->frameworkDirectories(); for (const QString& dir : directories) { Path path(dir); if (!list.contains(path)) { list << path; } } } } // make sure the base dir is included if (!list.contains(folder->path())) { list << folder->path(); } // qCDebug(KDEV_QMAKE) << "include dirs for" << item->path() << ":" << list; } return list; } Path::List QMakeProjectManager::includeDirectories(ProjectBaseItem* item) const { return collectDirectories(item); } Path::List QMakeProjectManager::frameworkDirectories(ProjectBaseItem* item) const { return collectDirectories(item, false); } QHash QMakeProjectManager::defines(ProjectBaseItem* item) const { QHash d; QMakeFolderItem* folder = findQMakeFolderParent(item); if (!folder) { // happens for bad qmake configurations return d; } foreach (QMakeProjectFile* pro, folder->projectFiles()) { foreach (QMakeProjectFile::DefinePair def, pro->defines()) { d.insert(def.first, def.second); } } return d; } QString QMakeProjectManager::extraArguments(KDevelop::ProjectBaseItem *item) const { QMakeFolderItem* folder = findQMakeFolderParent(item); if (!folder) { // happens for bad qmake configurations return {}; } QStringList d; foreach (QMakeProjectFile* pro, folder->projectFiles()) { d << pro->extraArguments(); } return d.join(QLatin1Char(' ')); } bool QMakeProjectManager::hasBuildInfo(KDevelop::ProjectBaseItem* item) const { return findQMakeFolderParent(item); } QMakeCache* QMakeProjectManager::findQMakeCache(IProject* project, const Path& path) const { QDir curdir(QMakeConfig::buildDirFromSrc(project, !path.isValid() ? project->path() : path).toLocalFile()); curdir.makeAbsolute(); while (!curdir.exists(QStringLiteral(".qmake.cache")) && !curdir.isRoot() && curdir.cdUp()) { qCDebug(KDEV_QMAKE) << curdir; } if (curdir.exists(QStringLiteral(".qmake.cache"))) { qCDebug(KDEV_QMAKE) << "Found QMake cache in " << curdir.absolutePath(); return new QMakeCache(curdir.canonicalPath() + QLatin1String("/.qmake.cache")); } return nullptr; } ContextMenuExtension QMakeProjectManager::contextMenuExtension(Context* context, QWidget* parent) { Q_UNUSED(parent); ContextMenuExtension ext; if (context->hasType(Context::ProjectItemContext)) { auto* pic = dynamic_cast(context); Q_ASSERT(pic); if (pic->items().isEmpty()) { return ext; } m_actionItem = dynamic_cast(pic->items().first()); if (m_actionItem) { ext.addAction(ContextMenuExtension::ProjectGroup, m_runQMake); } } return ext; } void QMakeProjectManager::slotRunQMake() { Q_ASSERT(m_actionItem); Path srcDir = m_actionItem->path(); Path buildDir = QMakeConfig::buildDirFromSrc(m_actionItem->project(), srcDir); QMakeJob* job = new QMakeJob(srcDir.toLocalFile(), buildDir.toLocalFile(), this); job->setQMakePath(QMakeConfig::qmakeExecutable(m_actionItem->project())); KConfigGroup cg(m_actionItem->project()->projectConfiguration(), QMakeConfig::CONFIG_GROUP); QString installPrefix = cg.readEntry(QMakeConfig::INSTALL_PREFIX, QString()); if (!installPrefix.isEmpty()) job->setInstallPrefix(installPrefix); job->setBuildType(cg.readEntry(QMakeConfig::BUILD_TYPE, 0)); job->setExtraArguments(cg.readEntry(QMakeConfig::EXTRA_ARGUMENTS, QString())); KDevelop::ICore::self()->runController()->registerJob(job); } KDevelop::Path QMakeProjectManager::compiler(KDevelop::ProjectTargetItem* p) const { + Q_UNUSED(p); return {}; } #include "qmakemanager.moc"