Warning, file /kdevelop/kdevelop/plugins/custom-definesandincludes/definesandincludesmanager.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2014 Sergey Kalinichev <kalinichev.so.0@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "definesandincludesmanager.h" 0008 0009 #include "kcm_widget/definesandincludesconfigpage.h" 0010 #include "compilerprovider/compilerprovider.h" 0011 #include "compilerprovider/widget/compilerswidget.h" 0012 #include "noprojectincludesanddefines/noprojectincludepathsmanager.h" 0013 0014 #include <interfaces/icore.h> 0015 #include <interfaces/iprojectcontroller.h> 0016 #include <interfaces/iproject.h> 0017 #include <project/interfaces/ibuildsystemmanager.h> 0018 #include <project/projectmodel.h> 0019 0020 #include <KPluginFactory> 0021 0022 #include <QThread> 0023 #include <QCoreApplication> 0024 0025 #include <algorithm> 0026 0027 using namespace KDevelop; 0028 0029 namespace 0030 { 0031 ///@return: The ConfigEntry, with includes/defines from @p paths for all parent folders of @p item. 0032 static ConfigEntry findConfigForItem(QVector<ConfigEntry> paths, const KDevelop::ProjectBaseItem* item) 0033 { 0034 ConfigEntry ret; 0035 0036 const Path itemPath = item->path(); 0037 const Path rootDirectory = item->project()->path(); 0038 Path closestPath; 0039 0040 std::sort(paths.begin(), paths.end(), [] (const ConfigEntry& lhs, const ConfigEntry& rhs) { 0041 // sort in reverse order to do a bottom-up search 0042 return lhs.path > rhs.path; 0043 }); 0044 0045 for (const ConfigEntry & entry : paths) { 0046 Path targetDirectory = rootDirectory; 0047 // note: a dot represents the project root 0048 if (entry.path != QLatin1String(".")) { 0049 targetDirectory.addPath(entry.path); 0050 } 0051 0052 if (targetDirectory == itemPath || targetDirectory.isParentOf(itemPath)) { 0053 ret.includes += entry.includes; 0054 0055 for (auto it = entry.defines.constBegin(); it != entry.defines.constEnd(); it++) { 0056 if (!ret.defines.contains(it.key())) { 0057 ret.defines[it.key()] = it.value(); 0058 } 0059 } 0060 0061 if (targetDirectory.segments().size() > closestPath.segments().size()) { 0062 ret.parserArguments = entry.parserArguments; 0063 closestPath = targetDirectory; 0064 } 0065 } 0066 } 0067 ret.includes.removeDuplicates(); 0068 0069 Q_ASSERT(!ret.parserArguments.isAnyEmpty()); 0070 0071 return ret; 0072 } 0073 0074 void merge(Defines* target, const Defines& source) 0075 { 0076 if (target->isEmpty()) { 0077 *target = source; 0078 return; 0079 } 0080 0081 for (auto it = source.constBegin(); it != source.constEnd(); ++it) { 0082 target->insert(it.key(), it.value()); 0083 } 0084 } 0085 0086 QString argumentsForPath(const QString& path, const ParserArguments& arguments) 0087 { 0088 auto languageType = Utils::languageType(path, arguments.parseAmbiguousAsCPP); 0089 if (languageType != Utils::Other) 0090 return arguments[languageType]; 0091 else 0092 return {}; 0093 } 0094 0095 } 0096 0097 K_PLUGIN_FACTORY_WITH_JSON(DefinesAndIncludesManagerFactory, "kdevdefinesandincludesmanager.json", registerPlugin<DefinesAndIncludesManager>(); ) 0098 0099 DefinesAndIncludesManager::DefinesAndIncludesManager( QObject* parent, const QVariantList& ) 0100 : IPlugin(QStringLiteral("kdevdefinesandincludesmanager"), parent ) 0101 , m_settings(SettingsManager::globalInstance()) 0102 , m_noProjectIPM(new NoProjectIncludePathsManager()) 0103 { 0104 registerProvider(m_settings->provider()); 0105 #ifdef Q_OS_OSX 0106 m_defaultFrameworkDirectories += Path(QStringLiteral("/Library/Frameworks")); 0107 m_defaultFrameworkDirectories += Path(QStringLiteral("/System/Library/Frameworks")); 0108 #endif 0109 } 0110 0111 DefinesAndIncludesManager::~DefinesAndIncludesManager() = default; 0112 0113 Defines DefinesAndIncludesManager::defines( ProjectBaseItem* item, Type type ) const 0114 { 0115 Q_ASSERT(QThread::currentThread() == qApp->thread()); 0116 0117 if (!item) { 0118 return m_settings->provider()->defines(nullptr); 0119 } 0120 0121 Defines defines; 0122 0123 for (auto provider : m_providers) { 0124 if (provider->type() & type) { 0125 merge(&defines, provider->defines(item)); 0126 } 0127 } 0128 0129 if ( type & ProjectSpecific ) { 0130 auto buildManager = item->project()->buildSystemManager(); 0131 if ( buildManager ) { 0132 merge(&defines, buildManager->defines(item)); 0133 } 0134 } 0135 0136 // Manually set defines have the highest priority and overwrite values of all other types of defines. 0137 if (type & UserDefined) { 0138 auto cfg = item->project()->projectConfiguration().data(); 0139 0140 merge(&defines, findConfigForItem(m_settings->readPaths(cfg), item).defines); 0141 } 0142 0143 merge(&defines, m_noProjectIPM->includesAndDefines(item->path().path()).second); 0144 0145 return defines; 0146 } 0147 0148 Path::List DefinesAndIncludesManager::includes( ProjectBaseItem* item, Type type ) const 0149 { 0150 Q_ASSERT(QThread::currentThread() == qApp->thread()); 0151 0152 if (!item) { 0153 return m_settings->provider()->includes(nullptr); 0154 } 0155 0156 Path::List includes; 0157 0158 if (type & UserDefined) { 0159 auto cfg = item->project()->projectConfiguration().data(); 0160 0161 includes += KDevelop::toPathList(findConfigForItem(m_settings->readPaths(cfg), item).includes); 0162 } 0163 0164 if ( type & ProjectSpecific ) { 0165 auto buildManager = item->project()->buildSystemManager(); 0166 if ( buildManager ) { 0167 includes += buildManager->includeDirectories(item); 0168 } 0169 } 0170 0171 for (auto provider : m_providers) { 0172 if ( !(provider->type() & type) ) { 0173 continue; 0174 } 0175 const auto newItems = provider->includes(item); 0176 if ( provider->type() & DefinesAndIncludesManager::CompilerSpecific ) { 0177 // If an item occurs in the "compiler specific" list, but was previously supplied 0178 // in the user include path list already, remove it from there. 0179 // Re-ordering the system include paths causes confusion in some cases. 0180 for (const auto& x : newItems) { 0181 includes.removeAll(x); 0182 } 0183 } 0184 includes += newItems; 0185 } 0186 0187 includes += m_noProjectIPM->includesAndDefines(item->path().path()).first; 0188 0189 return includes; 0190 } 0191 0192 Path::List DefinesAndIncludesManager::frameworkDirectories( ProjectBaseItem* item, Type type ) const 0193 { 0194 Q_ASSERT(QThread::currentThread() == qApp->thread()); 0195 0196 if (!item) { 0197 return m_settings->provider()->frameworkDirectories(nullptr); 0198 } 0199 0200 Path::List frameworkDirectories = m_defaultFrameworkDirectories; 0201 0202 if ( type & ProjectSpecific ) { 0203 auto buildManager = item->project()->buildSystemManager(); 0204 if ( buildManager ) { 0205 frameworkDirectories += buildManager->frameworkDirectories(item); 0206 } 0207 } 0208 0209 for (auto provider : m_providers) { 0210 if (provider->type() & type) { 0211 frameworkDirectories += provider->frameworkDirectories(item); 0212 } 0213 } 0214 0215 return frameworkDirectories; 0216 } 0217 0218 bool DefinesAndIncludesManager::unregisterProvider(IDefinesAndIncludesManager::Provider* provider) 0219 { 0220 int idx = m_providers.indexOf(provider); 0221 if (idx != -1) { 0222 m_providers.remove(idx); 0223 return true; 0224 } 0225 0226 return false; 0227 } 0228 0229 void DefinesAndIncludesManager::registerProvider(IDefinesAndIncludesManager::Provider* provider) 0230 { 0231 Q_ASSERT(provider); 0232 if (m_providers.contains(provider)) { 0233 return; 0234 } 0235 0236 m_providers.push_back(provider); 0237 } 0238 0239 Defines DefinesAndIncludesManager::defines(const QString& path, Type type) const 0240 { 0241 Defines ret; 0242 if ( type & CompilerSpecific ) { 0243 merge(&ret, m_settings->provider()->defines(path)); 0244 } 0245 if ( type & ProjectSpecific ) { 0246 merge(&ret, m_noProjectIPM->includesAndDefines(path).second); 0247 } 0248 return ret; 0249 } 0250 0251 Path::List DefinesAndIncludesManager::includes(const QString& path, Type type) const 0252 { 0253 Path::List ret; 0254 if ( type & CompilerSpecific ) { 0255 ret += m_settings->provider()->includes(path); 0256 } 0257 if ( type & ProjectSpecific ) { 0258 ret += m_noProjectIPM->includesAndDefines(path).first; 0259 } 0260 return ret; 0261 } 0262 0263 Path::List DefinesAndIncludesManager::frameworkDirectories(const QString& path, Type type) const 0264 { 0265 return (type & CompilerSpecific) ? m_settings->provider()->frameworkDirectories(path) : Path::List(); 0266 } 0267 0268 void DefinesAndIncludesManager::openConfigurationDialog(const QString& pathToFile) 0269 { 0270 if (auto project = KDevelop::ICore::self()->projectController()->findProjectForUrl(QUrl::fromLocalFile(pathToFile))) { 0271 KDevelop::ICore::self()->projectController()->configureProject(project); 0272 } else { 0273 m_noProjectIPM->openConfigurationDialog(pathToFile); 0274 } 0275 } 0276 0277 Path::List DefinesAndIncludesManager::includesInBackground(const QString& path) const 0278 { 0279 Path::List includes; 0280 0281 for (auto provider: m_backgroundProviders) { 0282 includes += provider->includesInBackground(path); 0283 } 0284 0285 return includes; 0286 } 0287 0288 Path::List DefinesAndIncludesManager::frameworkDirectoriesInBackground(const QString& path) const 0289 { 0290 Path::List fwDirs; 0291 0292 for (auto provider: m_backgroundProviders) { 0293 fwDirs += provider->frameworkDirectoriesInBackground(path); 0294 } 0295 0296 return fwDirs; 0297 } 0298 0299 Defines DefinesAndIncludesManager::definesInBackground(const QString& path) const 0300 { 0301 QHash<QString, QString> defines; 0302 0303 for (auto provider: m_backgroundProviders) { 0304 auto result = provider->definesInBackground(path); 0305 for (auto it = result.constBegin(); it != result.constEnd(); it++) { 0306 defines[it.key()] = it.value(); 0307 } 0308 } 0309 0310 merge(&defines, m_noProjectIPM->includesAndDefines(path).second); 0311 0312 return defines; 0313 } 0314 0315 bool DefinesAndIncludesManager::unregisterBackgroundProvider(IDefinesAndIncludesManager::BackgroundProvider* provider) 0316 { 0317 int idx = m_backgroundProviders.indexOf(provider); 0318 if (idx != -1) { 0319 m_backgroundProviders.remove(idx); 0320 return true; 0321 } 0322 0323 return false; 0324 } 0325 0326 void DefinesAndIncludesManager::registerBackgroundProvider(IDefinesAndIncludesManager::BackgroundProvider* provider) 0327 { 0328 Q_ASSERT(provider); 0329 if (m_backgroundProviders.contains(provider)) { 0330 return; 0331 } 0332 0333 m_backgroundProviders.push_back(provider); 0334 } 0335 0336 QString DefinesAndIncludesManager::parserArguments(KDevelop::ProjectBaseItem* item) const 0337 { 0338 Q_ASSERT(item); 0339 0340 Q_ASSERT(QThread::currentThread() == qApp->thread()); 0341 0342 auto cfg = item->project()->projectConfiguration().data(); 0343 const auto parserArguments = findConfigForItem(m_settings->readPaths(cfg), item).parserArguments; 0344 auto arguments = argumentsForPath(item->path().path(), parserArguments); 0345 0346 auto buildManager = item->project()->buildSystemManager(); 0347 if ( buildManager ) { 0348 const auto extraArguments = buildManager->extraArguments(item); 0349 if (!extraArguments.isEmpty()) 0350 arguments += QLatin1Char(' ') + extraArguments; 0351 } 0352 0353 return arguments; 0354 } 0355 0356 QString DefinesAndIncludesManager::parserArguments(const QString& path) const 0357 { 0358 const auto args = m_settings->defaultParserArguments(); 0359 return argumentsForPath(path, args); 0360 } 0361 0362 QString DefinesAndIncludesManager::parserArgumentsInBackground(const QString& path) const 0363 { 0364 QString ret; 0365 for (auto provider: m_backgroundProviders) { 0366 ret += provider->parserArgumentsInBackground(path) + QLatin1Char(' '); 0367 } 0368 0369 return ret; 0370 } 0371 0372 int DefinesAndIncludesManager::perProjectConfigPages() const 0373 { 0374 return 1; 0375 } 0376 0377 ConfigPage* DefinesAndIncludesManager::perProjectConfigPage(int number, const ProjectConfigOptions& options, QWidget* parent) 0378 { 0379 if (number == 0) { 0380 return new DefinesAndIncludesConfigPage(this, options, parent); 0381 } 0382 return nullptr; 0383 } 0384 0385 KDevelop::ConfigPage* DefinesAndIncludesManager::configPage(int number, QWidget* parent) 0386 { 0387 return number == 0 ? new CompilersWidget(parent) : nullptr; 0388 } 0389 0390 int DefinesAndIncludesManager::configPages() const 0391 { 0392 return 1; 0393 } 0394 0395 #include "definesandincludesmanager.moc" 0396 #include "moc_definesandincludesmanager.cpp"