File indexing completed on 2024-04-28 04:34:22
0001 /*************************************************************************** 0002 * Copyright 2009 Sandro Andrade <sandroandrade@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify * 0005 * it under the terms of the GNU Library General Public License as * 0006 * published by the Free Software Foundation; either version 2 of the * 0007 * License, or (at your option) any later version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, * 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0012 * GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU Library General Public * 0015 * License along with this program; if not, write to the * 0016 * Free Software Foundation, Inc., * 0017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0018 ***************************************************************************/ 0019 0020 #include "duchaincontrolflow.h" 0021 0022 #include <limits> 0023 0024 #include <KLocale> 0025 0026 #include <KTextEditor/View> 0027 #include <KTextEditor/Document> 0028 #include <KTextEditor/Cursor> 0029 0030 #include <interfaces/icore.h> 0031 #include <interfaces/iproject.h> 0032 #include <interfaces/iruncontroller.h> 0033 #include <interfaces/iprojectcontroller.h> 0034 #include <interfaces/ilanguagecontroller.h> 0035 #include <interfaces/idocumentcontroller.h> 0036 0037 #include <language/duchain/use.h> 0038 #include <language/duchain/duchain.h> 0039 #include <language/duchain/ducontext.h> 0040 #include <language/duchain/declaration.h> 0041 #include <language/duchain/duchainlock.h> 0042 #include <language/duchain/duchainutils.h> 0043 #include <language/duchain/indexedstring.h> 0044 #include <language/util/navigationtooltip.h> 0045 #include <language/duchain/functiondefinition.h> 0046 #include <language/duchain/types/functiontype.h> 0047 #include <language/backgroundparser/backgroundparser.h> 0048 0049 #include <project/projectmodel.h> 0050 #include <project/interfaces/ibuildsystemmanager.h> 0051 0052 #include "dotcontrolflowgraph.h" 0053 #include "duchaincontrolflowjob.h" 0054 #include "controlflowgraphusescollector.h" 0055 #include "controlflowgraphnavigationwidget.h" 0056 0057 Q_DECLARE_METATYPE(KDevelop::Use) 0058 0059 using namespace KDevelop; 0060 0061 DUChainControlFlow::DUChainControlFlow(DotControlFlowGraph* dotControlFlowGraph) 0062 : m_dotControlFlowGraph(dotControlFlowGraph), 0063 m_previousUppermostExecutableContext(IndexedDUContext()), 0064 m_currentView(0), 0065 m_currentProject(0), 0066 m_currentLevel(1), 0067 m_maxLevel(2), 0068 m_locked(false), 0069 m_drawIncomingArcs(true), 0070 m_useFolderName(true), 0071 m_useShortNames(true), 0072 m_ShowUsesOnEdgeHover(true), 0073 m_controlFlowMode(ControlFlowClass), 0074 m_clusteringModes(ClusteringNamespace), 0075 m_graphThreadRunning(false), 0076 m_abort(false), 0077 m_collector(0) 0078 { 0079 qRegisterMetaType<Use>("Use"); 0080 } 0081 0082 DUChainControlFlow::~DUChainControlFlow() 0083 { 0084 KDevelop::ICore::self()->languageController()->backgroundParser()->revertAllRequests(this); 0085 delete m_collector; 0086 } 0087 0088 void DUChainControlFlow::setControlFlowMode(ControlFlowMode controlFlowMode) 0089 { 0090 m_controlFlowMode = controlFlowMode; 0091 } 0092 0093 void DUChainControlFlow::setClusteringModes(ClusteringModes clusteringModes) 0094 { 0095 m_clusteringModes = clusteringModes; 0096 } 0097 0098 DUChainControlFlow::ClusteringModes DUChainControlFlow::clusteringModes() const 0099 { 0100 return m_clusteringModes; 0101 } 0102 0103 void DUChainControlFlow::generateControlFlowForDeclaration(IndexedDeclaration idefinition, IndexedTopDUContext itopContext, IndexedDUContext iuppermostExecutableContext) 0104 { 0105 DUChainReadLocker lock(DUChain::lock()); 0106 0107 Declaration *definition = idefinition.data(); 0108 if (!definition) 0109 return; 0110 0111 TopDUContext *topContext = itopContext.data(); 0112 if (!topContext) 0113 return; 0114 0115 DUContext *uppermostExecutableContext = iuppermostExecutableContext.data(); 0116 if (!uppermostExecutableContext) 0117 return; 0118 0119 // Convert to a declaration in accordance with control flow mode (function, class or namespace) 0120 Declaration *nodeDefinition = declarationFromControlFlowMode(definition); 0121 0122 QStringList containers; 0123 prepareContainers(containers, definition); 0124 0125 QString shortName = shortNameFromContainers(containers, prependFolderNames(nodeDefinition)); 0126 0127 if (m_maxLevel != 1 && !m_visitedFunctions.contains(idefinition) && nodeDefinition && nodeDefinition->internalContext()) 0128 { 0129 m_dotControlFlowGraph->foundRootNode(containers, (m_controlFlowMode == ControlFlowNamespace && 0130 nodeDefinition->internalContext() && nodeDefinition->internalContext()->type() != DUContext::Namespace) ? 0131 globalNamespaceOrFolderNames(nodeDefinition): 0132 shortName); 0133 ++m_currentLevel; 0134 m_visitedFunctions.insert(idefinition); 0135 m_identifierDeclarationMap[containers.join("") + shortName] = IndexedDeclaration(nodeDefinition); 0136 useDeclarationsFromDefinition(definition, topContext, uppermostExecutableContext); 0137 } 0138 0139 if (m_abort) 0140 return; 0141 0142 if (m_drawIncomingArcs) 0143 { 0144 Declaration *declaration = definition; 0145 if (declaration->isDefinition()) 0146 declaration = DUChainUtils::declarationForDefinition(declaration, topContext); 0147 0148 if (declaration) 0149 { 0150 delete m_collector; 0151 m_collector = new ControlFlowGraphUsesCollector(declaration); 0152 m_collector->setProcessDeclarations(true); 0153 connect(m_collector, SIGNAL(processFunctionCall(Declaration*, Declaration*, Use)), SLOT(processFunctionCall(Declaration*, Declaration*, Use))); 0154 m_collector->startCollecting(); 0155 } 0156 } 0157 0158 m_dotControlFlowGraph->graphDone(); 0159 m_currentLevel = 1; 0160 } 0161 0162 bool DUChainControlFlow::isLocked() 0163 { 0164 return m_locked; 0165 } 0166 0167 void DUChainControlFlow::run() 0168 { 0169 DUChainReadLocker lock(DUChain::lock()); 0170 0171 m_abort = false; 0172 generateControlFlowForDeclaration(m_definition, m_topContext, m_uppermostExecutableContext); 0173 } 0174 0175 void DUChainControlFlow::cursorPositionChanged(KTextEditor::View *view, const KTextEditor::Cursor &cursor) 0176 { 0177 if (!m_graphThreadRunning) 0178 { 0179 if (m_locked) return; 0180 if (!view->document()) return; 0181 0182 DUChainReadLocker lock(DUChain::lock()); 0183 0184 TopDUContext *topContext = DUChainUtils::standardContextForUrl(view->document()->url()); 0185 if (!topContext) return; 0186 0187 DUContext *context = topContext->findContextAt(topContext->transformToLocalRevision(KDevelop::SimpleCursor(cursor))); 0188 0189 if (!context) 0190 { 0191 newGraph(); 0192 m_previousUppermostExecutableContext = IndexedDUContext(); 0193 return; 0194 } 0195 0196 // If cursor is in a method arguments context change it to internal context 0197 if (context && context->type() == DUContext::Function && context->importers().size() == 1) 0198 context = context->importers()[0]; 0199 0200 Declaration *declarationUnderCursor = DUChainUtils::itemUnderCursor(view->document()->url(), KDevelop::SimpleCursor(cursor)); 0201 if (declarationUnderCursor && (!context || context->type() != DUContext::Other) && declarationUnderCursor->internalContext()) 0202 context = declarationUnderCursor->internalContext(); 0203 0204 if (!context || context->type() != DUContext::Other) 0205 { 0206 // If there is a previous graph 0207 if (!(m_previousUppermostExecutableContext == IndexedDUContext())) 0208 { 0209 newGraph(); 0210 m_previousUppermostExecutableContext = IndexedDUContext(); 0211 } 0212 return; 0213 } 0214 0215 m_currentContext = IndexedDUContext(context); 0216 m_currentView = view; 0217 m_topContext = IndexedTopDUContext(topContext); 0218 0219 m_currentProject = ICore::self()->projectController()->findProjectForUrl(m_currentView->document()->url()); 0220 m_includeDirectories.clear(); 0221 0222 // Invoke includeDirectories in advance. Running it in the background thread may crash because 0223 // of thread-safety issues in KConfig / CMakeUtils. 0224 if (m_currentProject) 0225 { 0226 KDevelop::ProjectBaseItem *project_item = m_currentProject->projectItem(); 0227 IBuildSystemManager *buildSystemManager = 0; 0228 if (project_item && (buildSystemManager = m_currentProject->buildSystemManager())) 0229 m_includeDirectories = buildSystemManager->includeDirectories(project_item); 0230 } 0231 0232 // Navigate to uppermost executable context 0233 DUContext *uppermostExecutableContext = m_currentContext.data(); 0234 if (!uppermostExecutableContext) 0235 return; 0236 0237 while (uppermostExecutableContext->parentContext() && uppermostExecutableContext->parentContext()->type() == DUContext::Other) 0238 uppermostExecutableContext = uppermostExecutableContext->parentContext(); 0239 0240 // If cursor is in the same function definition 0241 if (IndexedDUContext(uppermostExecutableContext) == m_previousUppermostExecutableContext) 0242 return; 0243 0244 m_previousUppermostExecutableContext = IndexedDUContext(uppermostExecutableContext); 0245 0246 // Get the definition 0247 Declaration* definition = 0; 0248 if (!uppermostExecutableContext || !uppermostExecutableContext->owner()) 0249 return; 0250 else 0251 definition = uppermostExecutableContext->owner(); 0252 0253 if (!definition) return; 0254 0255 newGraph(); 0256 m_dotControlFlowGraph->prepareNewGraph(); 0257 0258 m_definition = IndexedDeclaration(definition); 0259 m_uppermostExecutableContext = IndexedDUContext(uppermostExecutableContext); 0260 0261 m_graphThreadRunning = true; 0262 DUChainControlFlowJob *job = new DUChainControlFlowJob(context->scopeIdentifier().toString(), this); 0263 connect (job, SIGNAL(result(KJob*)), SLOT(jobDone(KJob*))); 0264 emit startingJob(); 0265 ICore::self()->runController()->registerJob(job); 0266 } 0267 else 0268 kDebug() << "Control flow thread already running"; 0269 } 0270 0271 void DUChainControlFlow::processFunctionCall(Declaration *source, Declaration *target, const Use &use) 0272 { 0273 FunctionDefinition *calledFunctionDefinition; 0274 DUContext *calledFunctionContext; 0275 0276 DUChainReadLocker lock(DUChain::lock()); 0277 0278 // Convert to a declaration in accordance with control flow mode (function, class or namespace) 0279 Declaration *nodeSource = declarationFromControlFlowMode(source); 0280 Declaration *nodeTarget = declarationFromControlFlowMode(target); 0281 0282 // Try to acquire the called function definition 0283 calledFunctionDefinition = FunctionDefinition::definition(target); 0284 0285 QStringList sourceContainers, targetContainers; 0286 0287 prepareContainers(sourceContainers, source); 0288 prepareContainers(targetContainers, target); 0289 0290 QString sourceLabel = shortNameFromContainers(sourceContainers, 0291 (m_controlFlowMode == ControlFlowNamespace && 0292 (nodeSource->internalContext() && nodeSource->internalContext()->type() != DUContext::Namespace)) ? 0293 globalNamespaceOrFolderNames(nodeSource) : 0294 prependFolderNames(nodeSource)); 0295 0296 QString targetLabel = shortNameFromContainers(targetContainers, 0297 (m_controlFlowMode == ControlFlowNamespace && 0298 (nodeTarget->internalContext() && nodeTarget->internalContext()->type() != DUContext::Namespace)) ? 0299 globalNamespaceOrFolderNames(nodeTarget) : 0300 prependFolderNames(nodeTarget)); 0301 0302 QString sourceShortName = shortNameFromContainers(sourceContainers, prependFolderNames(nodeSource)); 0303 QString targetShortName = shortNameFromContainers(targetContainers, prependFolderNames(nodeTarget)); 0304 0305 if (sender() && dynamic_cast<ControlFlowGraphUsesCollector *>(sender())) 0306 { 0307 sourceContainers.prepend(i18n("Uses of %1", targetLabel)); 0308 m_identifierDeclarationMap[sourceContainers.join("") + sourceShortName] = IndexedDeclaration(nodeSource); 0309 } 0310 0311 IndexedDeclaration ideclaration = IndexedDeclaration(calledFunctionDefinition); 0312 m_dotControlFlowGraph->foundFunctionCall(sourceContainers, sourceLabel, targetContainers, targetLabel); 0313 0314 if (calledFunctionDefinition) 0315 calledFunctionContext = calledFunctionDefinition->internalContext(); 0316 else 0317 { 0318 // Store method declaration for navigation 0319 m_identifierDeclarationMap[targetContainers.join("") + targetShortName] = IndexedDeclaration(nodeTarget); 0320 // Store use for edge inspection 0321 QPair<RangeInRevision, IndexedString> pair(use.m_range, source->url()); 0322 if (!m_arcUsesMap.values(sourceLabel + "->" + targetLabel).contains(pair)) 0323 m_arcUsesMap.insertMulti(sourceLabel + "->" + targetLabel, pair); 0324 return; 0325 } 0326 0327 // Store use for edge inspection 0328 QPair<RangeInRevision, IndexedString> pair(use.m_range, source->url()); 0329 if (!m_arcUsesMap.values(sourceLabel + "->" + targetLabel).contains(pair)) 0330 m_arcUsesMap.insertMulti(sourceLabel + "->" + targetLabel, pair); 0331 // Store method definition for navigation 0332 m_identifierDeclarationMap[targetContainers.join("") + targetShortName] = IndexedDeclaration(declarationFromControlFlowMode(calledFunctionDefinition)); 0333 0334 if (calledFunctionContext && (m_currentLevel < m_maxLevel || m_maxLevel == 0)) 0335 { 0336 // For prevent endless loop in recursive methods 0337 if (!m_visitedFunctions.contains(ideclaration)) 0338 { 0339 ++m_currentLevel; 0340 m_visitedFunctions.insert(ideclaration); 0341 // Recursive call for method invocation 0342 useDeclarationsFromDefinition(calledFunctionDefinition, calledFunctionDefinition->topContext(), calledFunctionContext); 0343 } 0344 } 0345 } 0346 0347 void DUChainControlFlow::updateToolTip(const QString &edge, const QPoint& point, QWidget *partWidget) 0348 { 0349 ControlFlowGraphNavigationWidget *navigationWidget = 0350 new ControlFlowGraphNavigationWidget(edge, m_arcUsesMap.values(edge)); 0351 0352 KDevelop::NavigationToolTip *usesToolTip = new KDevelop::NavigationToolTip( 0353 partWidget, 0354 point, 0355 navigationWidget); 0356 0357 usesToolTip->resize(navigationWidget->sizeHint() + QSize(10, 10)); 0358 ActiveToolTip::showToolTip(usesToolTip, 100, edge); 0359 } 0360 0361 void DUChainControlFlow::slotGraphElementSelected(QList<QString> list, const QPoint& point) 0362 { 0363 Q_UNUSED(point) 0364 if (!list.isEmpty()) 0365 { 0366 QString label = list[0]; 0367 Declaration *declaration = m_identifierDeclarationMap[label].data(); 0368 0369 DUChainReadLocker lock(DUChain::lock()); 0370 0371 if (declaration) // Node click, jump to definition/declaration 0372 { 0373 KUrl url(declaration->url().str()); 0374 CursorInRevision cursor = declaration->range().start; 0375 int line = cursor.line; 0376 int column = cursor.column; 0377 0378 lock.unlock(); 0379 0380 ICore::self()->documentController()->openDocument(url, KTextEditor::Cursor(line, column)); 0381 } 0382 } 0383 } 0384 0385 void DUChainControlFlow::slotEdgeHover(QString label) 0386 { 0387 if (label.contains("->") && m_ShowUsesOnEdgeHover) // Edge click, show uses contained in the edge 0388 { 0389 KParts::ReadOnlyPart *part = dynamic_cast<KParts::ReadOnlyPart *>(sender()); 0390 if (!part) 0391 return; 0392 updateToolTip(label, QCursor::pos(), part->widget()); 0393 } 0394 } 0395 0396 void DUChainControlFlow::setLocked(bool locked) 0397 { 0398 m_locked = locked; 0399 } 0400 0401 void DUChainControlFlow::setUseFolderName(bool useFolderName) 0402 { 0403 m_useFolderName = useFolderName; 0404 } 0405 0406 void DUChainControlFlow::setUseShortNames(bool useShortNames) 0407 { 0408 m_useShortNames = useShortNames; 0409 } 0410 0411 void DUChainControlFlow::setDrawIncomingArcs(bool drawIncomingArcs) 0412 { 0413 m_drawIncomingArcs = drawIncomingArcs; 0414 } 0415 0416 void DUChainControlFlow::setMaxLevel(int maxLevel) 0417 { 0418 m_maxLevel = maxLevel; 0419 } 0420 0421 void DUChainControlFlow::setShowUsesOnEdgeHover(bool checked) 0422 { 0423 m_ShowUsesOnEdgeHover = checked; 0424 } 0425 0426 void DUChainControlFlow::refreshGraph() 0427 { 0428 if (!m_locked) 0429 { 0430 if(ICore::self()->documentController()->activeDocument() && 0431 ICore::self()->documentController()->activeDocument()->textDocument() && 0432 ICore::self()->documentController()->activeDocument()->textDocument()->activeView()) 0433 { 0434 { 0435 DUChainReadLocker lock(DUChain::lock()); 0436 m_previousUppermostExecutableContext = IndexedDUContext(); 0437 } 0438 KTextEditor::View *view = ICore::self()->documentController()->activeDocument()->textDocument()->activeView(); 0439 cursorPositionChanged(view, view->cursorPosition()); 0440 } 0441 } 0442 } 0443 0444 void DUChainControlFlow::newGraph() 0445 { 0446 m_visitedFunctions.clear(); 0447 m_identifierDeclarationMap.clear(); 0448 m_arcUsesMap.clear(); 0449 m_currentProject = 0; 0450 m_dotControlFlowGraph->clearGraph(); 0451 } 0452 0453 void DUChainControlFlow::jobDone (KJob* job) 0454 { 0455 m_graphThreadRunning = false; 0456 job->deleteLater(); 0457 emit jobDone(); 0458 } 0459 0460 void DUChainControlFlow::useDeclarationsFromDefinition (Declaration *definition, TopDUContext *topContext, DUContext *context) 0461 { 0462 if (!topContext) return; 0463 0464 const Use *uses = context->uses(); 0465 unsigned int usesCount = context->usesCount(); 0466 QVector<DUContext *> subContexts = context->childContexts(); 0467 QVector<DUContext *>::iterator subContextsIterator = subContexts.begin(); 0468 QVector<DUContext *>::iterator subContextsEnd = subContexts.end(); 0469 0470 Declaration *declaration; 0471 for (unsigned int i = 0; i < usesCount; ++i) 0472 { 0473 if (m_abort) 0474 return; 0475 0476 declaration = topContext->usedDeclarationForIndex(uses[i].m_declarationIndex); 0477 if (declaration && declaration->type<KDevelop::FunctionType>()) 0478 { 0479 if (subContextsIterator != subContextsEnd) 0480 { 0481 if (uses[i].m_range.start < (*subContextsIterator)->range().start) 0482 processFunctionCall(definition, declaration, uses[i]); 0483 else if ((*subContextsIterator)->type() == DUContext::Other) 0484 { 0485 // Recursive call for sub-contexts 0486 useDeclarationsFromDefinition(definition, topContext, *subContextsIterator); 0487 ++subContextsIterator; 0488 --i; 0489 } 0490 } 0491 else 0492 processFunctionCall(definition, declaration, uses[i]); 0493 } 0494 } 0495 while (subContextsIterator != subContextsEnd) 0496 if ((*subContextsIterator)->type() == DUContext::Other) 0497 { 0498 // Recursive call for remaining sub-contexts 0499 useDeclarationsFromDefinition(definition, topContext, *subContextsIterator); 0500 ++subContextsIterator; 0501 } 0502 } 0503 0504 Declaration *DUChainControlFlow::declarationFromControlFlowMode(Declaration *definitionDeclaration) 0505 { 0506 Declaration *nodeDeclaration = definitionDeclaration; 0507 0508 if (m_controlFlowMode != ControlFlowFunction) 0509 { 0510 if (nodeDeclaration->isDefinition()) 0511 nodeDeclaration = DUChainUtils::declarationForDefinition(nodeDeclaration, nodeDeclaration->topContext()); 0512 if (!nodeDeclaration || !nodeDeclaration->context() || !nodeDeclaration->context()->owner()) return definitionDeclaration; 0513 while (nodeDeclaration->context() && 0514 nodeDeclaration->context()->owner() && 0515 ((m_controlFlowMode == ControlFlowClass && nodeDeclaration->context() && nodeDeclaration->context()->type() == DUContext::Class) || 0516 (m_controlFlowMode == ControlFlowNamespace && ( 0517 (nodeDeclaration->context() && nodeDeclaration->context()->type() == DUContext::Class) || 0518 (nodeDeclaration->context() && nodeDeclaration->context()->type() == DUContext::Namespace)) 0519 ))) 0520 nodeDeclaration = nodeDeclaration->context()->owner(); 0521 } 0522 return nodeDeclaration; 0523 } 0524 0525 void DUChainControlFlow::prepareContainers(QStringList &containers, Declaration* definition) 0526 { 0527 ControlFlowMode originalControlFlowMode = m_controlFlowMode; 0528 QString strGlobalNamespaceOrFolderNames; 0529 0530 // Handling project clustering 0531 if (m_clusteringModes.testFlag(ClusteringProject) && ICore::self()->projectController()->findProjectForUrl(definition->url().str())) 0532 containers << ICore::self()->projectController()->findProjectForUrl(definition->url().str())->name(); 0533 0534 // Handling namespace clustering 0535 if (m_clusteringModes.testFlag(ClusteringNamespace)) 0536 { 0537 m_controlFlowMode = ControlFlowNamespace; 0538 Declaration *namespaceDefinition = declarationFromControlFlowMode(definition); 0539 0540 strGlobalNamespaceOrFolderNames = ((namespaceDefinition->internalContext() && namespaceDefinition->internalContext()->type() != DUContext::Namespace) ? 0541 globalNamespaceOrFolderNames(namespaceDefinition): 0542 shortNameFromContainers(containers, prependFolderNames(namespaceDefinition))); 0543 foreach(const QString &container, strGlobalNamespaceOrFolderNames.split("::")) 0544 containers << container; 0545 } 0546 0547 // Handling class clustering 0548 if (m_clusteringModes.testFlag(ClusteringClass)) 0549 { 0550 m_controlFlowMode = ControlFlowClass; 0551 Declaration *classDefinition = declarationFromControlFlowMode(definition); 0552 0553 if (classDefinition->internalContext() && classDefinition->internalContext()->type() == DUContext::Class) 0554 containers << shortNameFromContainers(containers, prependFolderNames(classDefinition)); 0555 } 0556 0557 m_controlFlowMode = originalControlFlowMode; 0558 } 0559 0560 QString DUChainControlFlow::globalNamespaceOrFolderNames(Declaration *declaration) 0561 { 0562 if (m_useFolderName && m_currentProject && m_includeDirectories.count() > 0) 0563 { 0564 int minLength = std::numeric_limits<int>::max(); 0565 0566 QString folderName, smallestDirectory, declarationUrl = declaration->url().str(); 0567 0568 foreach (const Path &url, m_includeDirectories) 0569 { 0570 QString urlString = url.toLocalFile(); 0571 if (urlString.length() <= minLength && declarationUrl.startsWith(urlString)) 0572 { 0573 smallestDirectory = urlString; 0574 minLength = urlString.length(); 0575 } 0576 } 0577 declarationUrl = declarationUrl.remove(0, smallestDirectory.length()); 0578 declarationUrl = declarationUrl.remove(KUrl(declaration->url().str()).fileName()); 0579 if (declarationUrl.endsWith('/')) 0580 declarationUrl.chop(1); 0581 if (declarationUrl.startsWith('/')) 0582 declarationUrl.remove(0, 1); 0583 declarationUrl = declarationUrl.replace('/', "::"); 0584 if (!declarationUrl.isEmpty()) 0585 return declarationUrl; 0586 } 0587 return i18n("Global Namespace"); 0588 } 0589 0590 QString DUChainControlFlow::prependFolderNames(Declaration *declaration) 0591 { 0592 QString prependedQualifiedName = declaration->qualifiedIdentifier().toString(); 0593 if (m_useFolderName) 0594 { 0595 ControlFlowMode originalControlFlowMode = m_controlFlowMode; 0596 m_controlFlowMode = ControlFlowNamespace; 0597 Declaration *namespaceDefinition = declarationFromControlFlowMode(declaration); 0598 m_controlFlowMode = originalControlFlowMode; 0599 0600 QString prefix = globalNamespaceOrFolderNames(namespaceDefinition); 0601 0602 if (namespaceDefinition && namespaceDefinition->internalContext() && 0603 namespaceDefinition->internalContext()->type() != DUContext::Namespace && 0604 prefix != i18n("Global Namespace")) 0605 prependedQualifiedName.prepend(prefix + "::"); 0606 } 0607 0608 return prependedQualifiedName; 0609 } 0610 0611 QString DUChainControlFlow::shortNameFromContainers(const QList<QString> &containers, const QString &qualifiedIdentifier) 0612 { 0613 QString shortName = qualifiedIdentifier; 0614 0615 if (m_useShortNames) 0616 { 0617 foreach(const QString &container, containers) 0618 if (shortName.contains(container)) 0619 shortName.remove(shortName.indexOf(container + "::"), (container + "::").length()); 0620 } 0621 return shortName; 0622 }