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 }