• Skip to content
  • Skip to link menu
KDE 4.4 API Reference
  • KDE API Reference
  • KDevelop Platform Libraries
  • Sitemap
  • Contact Us
 

language/duchain

abstractusebuilder.h

00001 /* This file is part of KDevelop
00002     Copyright 2006-2008 Hamish Rodda <rodda@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #ifndef ABSTRACTUSEBUILDER_H
00020 #define ABSTRACTUSEBUILDER_H
00021 
00022 #include "../declaration.h"
00023 #include "../use.h"
00024 #include "../topducontext.h"
00025 #include "../duchain.h"
00026 #include "../duchainlock.h"
00027 
00028 #include <language/editor/editorintegrator.h>
00029 #include <ktexteditor/smartinterface.h>
00030 
00031 namespace KDevelop {
00032 
00043 template<typename T, typename NameT, typename LanguageSpecificUseBuilderBase>
00044 class AbstractUseBuilder: public LanguageSpecificUseBuilderBase
00045 {
00046 public:
00048   AbstractUseBuilder()
00049     : m_finishContext(true)
00050   {
00051   }
00052 
00059   void buildUses(T *node)
00060   {
00061     TopDUContext* top = dynamic_cast<TopDUContext*>(contextFromNode(node));
00062 
00063     if (top) {
00064       DUChainWriteLocker lock(DUChain::lock());
00065       top->clearUsedDeclarationIndices();
00066       if(top->features() & TopDUContext::AllDeclarationsContextsAndUses)
00067         LanguageSpecificUseBuilderBase::setRecompiling(true);
00068     }
00069 
00070     LanguageSpecificUseBuilderBase::supportBuild(node);
00071   }
00072 
00073 protected:
00080   struct ContextUseTracker {
00081     QSet<KTextEditor::SmartRange*> reuseRanges;
00082     QList<QPair<KDevelop::Use, KTextEditor::SmartRange*> > createUses;
00083   };
00084   
00085   void newUse(NameT* name)
00086   {
00087     QualifiedIdentifier id = identifierForNode(name);
00088 
00089     SimpleRange newRange = editorFindRange(name, name);
00090 
00091     DUChainWriteLocker lock(DUChain::lock()); 
00092     QList<Declaration*> declarations = LanguageSpecificUseBuilderBase::currentContext()->findDeclarations(id, newRange.start);
00093     foreach (Declaration* declaration, declarations)
00094       if (!declaration->isForwardDeclaration()) {
00095         declarations.clear();
00096         declarations.append(declaration);
00097         break;
00098       }
00099     // If we don't break, there's no non-forward declaration
00100 
00101     lock.unlock();
00102     newUse( name, newRange, !declarations.isEmpty() ? declarations.first() : 0 );
00103   }
00104 
00106 
00113   void newUse(T* node, KDevelop::Declaration* declaration)
00114   {
00115     newUse(node, editorFindRange(node, node), declaration);
00116   }
00117 
00124   void newUse(T* node, const SimpleRange& newRange, Declaration* declaration)
00125   {
00126     DUChainWriteLocker lock(DUChain::lock());
00127 
00128     bool encountered = false; 
00129     int declarationIndex = LanguageSpecificUseBuilderBase::currentContext()->topContext()->indexForUsedDeclaration(declaration);
00130     int contextUpSteps = 0; //We've got to use the stack here, and not parentContext(), because the order may be different
00131 
00132     {
00133       //We've got to consider the translated range, and while we use it, the smart-mutex needs to be locked
00134       LockedSmartInterface iface = LanguageSpecificUseBuilderBase::editor()->smart();
00135       SimpleRange translated = LanguageSpecificUseBuilderBase::editor()->translate(iface, newRange);
00136       
00137 //       if(iface)
00138 //         kDebug() << "translated by" << (translated.start.textCursor() - newRange.start.textCursor()) << (translated.end.textCursor() - newRange.end.textCursor()) << "to revision" << iface->currentRevision();
00139       
00140       KTextEditor::Range textTranslated  = translated.textRange();
00141 
00142       /*
00143       * We need to find a context that this use fits into, which must not necessarily be the current one.
00144       * The reason are macros like SOME_MACRO(SomeClass), where SomeClass is expanded to be within a
00145       * sub-context that comes from the macro. That sub-context will have a very small range, and will most
00146       * probably not be the range of the actual "SomeClass" text, so the "SomeClass" use has to be moved
00147       * into the context that surrounds the SOME_MACRO invocation.
00148       * */
00149       DUContext* newContext = LanguageSpecificUseBuilderBase::currentContext();
00150       while (!newContext->range().contains(translated) && contextUpSteps < (LanguageSpecificUseBuilderBase::contextStack().size()-1)) {
00151         ++contextUpSteps;
00152         newContext = LanguageSpecificUseBuilderBase::contextStack()[LanguageSpecificUseBuilderBase::contextStack().size()-1-contextUpSteps];
00153       }
00154       
00155       KTextEditor::SmartRange* use = 0;
00156 
00157       if (contextUpSteps) {
00158         LanguageSpecificUseBuilderBase::editor()->setCurrentRange(iface, newContext->smartRange()); //We have to do this, because later we will call closeContext(), and that will close one smart-range
00159         m_finishContext = false;
00160         openContext(newContext);
00161         m_finishContext = true;
00162         currentUseTracker() = m_trackerStack.at(m_trackerStack.size()-contextUpSteps-2);
00163 
00164         Q_ASSERT(m_contexts[m_trackerStack.size()-contextUpSteps-2] == LanguageSpecificUseBuilderBase::currentContext());
00165       }
00166 
00167       if (LanguageSpecificUseBuilderBase::recompiling() && this->currentContext()->smartRange()) {
00168 
00169         //Find a smart-range that we can reuse
00170         KTextEditor::SmartRange* containerRange = this->currentContext()->smartRange();
00171         KTextEditor::SmartRange* child  = containerRange->mostSpecificRange(textTranslated);
00172         while(child && child->parentRange() != containerRange)
00173           child = child->parentRange();
00174         
00175         //Solution for multiple equal ranges or ranges ending at the same position
00176         while(child && child->end() == textTranslated.end() && (!currentUseTracker().reuseRanges.contains(child) || *child != textTranslated))
00177           child = containerRange->childAfter(child);
00178         
00179         if(child && *child == textTranslated && currentUseTracker().reuseRanges.contains(child)) {
00180           //We found a range to re-use
00181           currentUseTracker().reuseRanges.remove(child);
00182           use = child;
00183         }
00184       }
00185       if (!encountered) {
00186         if(!use) {
00187           use = LanguageSpecificUseBuilderBase::editor()->currentRange(iface) ? LanguageSpecificUseBuilderBase::editor()->createRange(iface, newRange.textRange()) : 0;
00188           LanguageSpecificUseBuilderBase::editor()->exitCurrentRange(iface);
00189         }
00190         
00191         if (LanguageSpecificUseBuilderBase::m_mapAst)
00192           LanguageSpecificUseBuilderBase::editor()->parseSession()->mapAstUse(
00193             node, qMakePair<DUContextPointer, SimpleRange>(DUContextPointer(newContext), newRange));
00194 
00195         currentUseTracker().createUses << qMakePair(KDevelop::Use(newRange, declarationIndex), use);
00196       }
00197     }
00198 
00199     if (contextUpSteps) {
00200       Q_ASSERT(m_contexts[m_trackerStack.size()-contextUpSteps-2] == LanguageSpecificUseBuilderBase::currentContext());
00201       m_trackerStack[m_trackerStack.size()-contextUpSteps-2] = currentUseTracker();
00202       m_finishContext = false;
00203       closeContext();
00204       m_finishContext = true;
00205     }
00206   }
00207 
00211   virtual void openContext(KDevelop::DUContext* newContext)
00212   {
00213     LanguageSpecificUseBuilderBase::openContext(newContext);
00214 
00215     DUChainWriteLocker lock(DUChain::lock());
00216     LockedSmartInterface iface = LanguageSpecificUseBuilderBase::editor()->smart();
00217     
00218     ContextUseTracker newTracker;
00219     foreach(KTextEditor::SmartRange* range, newContext->useRanges())
00220       newTracker.reuseRanges.insert(range);
00221     
00222     m_trackerStack.push(newTracker);
00223     m_contexts.push(newContext);
00224   }
00225 
00229   virtual void closeContext()
00230   {
00231     if(m_finishContext) {
00232       DUChainWriteLocker lock(DUChain::lock());
00233 
00234       LockedSmartInterface iface = LanguageSpecificUseBuilderBase::editor()->smart();
00235       //Delete all ranges that were not re-used
00236       if(this->currentContext()->smartRange() && iface) {
00237         this->currentContext()->takeUseRanges();
00238         foreach(KTextEditor::SmartRange* range, currentUseTracker().reuseRanges) {
00239 #ifdef DEBUG_UPDATE_MATCHING
00240           if(!range->isEmpty()) //we cannot find empty ranges, so don't give warnings for them
00241             kDebug() << "deleting not re-used range:" << *range;
00242 #endif
00243           delete range;
00244         }
00245       }
00246       
00247       this->currentContext()->deleteUses();
00248       
00249       Q_ASSERT(this->currentContext()->usesCount() == 0);
00250       
00251       ContextUseTracker& tracker(currentUseTracker());
00252       for(int a = 0; a < tracker.createUses.size(); ++a) {
00253         KTextEditor::SmartRange* range = 0;
00254         
00255         if(this->currentContext()->smartRange() && iface) {
00256           range = tracker.createUses[a].second;
00257           Q_ASSERT(range);
00258         }
00259         
00260         Q_ASSERT(this->currentContext()->usesCount() == a);
00261         this->currentContext()->createUse(tracker.createUses[a].first.m_declarationIndex, tracker.createUses[a].first.m_range, range);
00262       }
00263       
00264     }
00265 
00266     LanguageSpecificUseBuilderBase::closeContext();
00267 
00268     m_trackerStack.pop();
00269     m_contexts.pop();
00270   }
00271 
00272 private:
00273   inline ContextUseTracker& currentUseTracker() { return m_trackerStack.top(); }
00274   QStack<ContextUseTracker> m_trackerStack;
00275   QStack<KDevelop::DUContext*> m_contexts;
00276 
00277   //Whether not encountered uses should be deleted during closeContext()
00278   bool m_finishContext;
00279 };
00280 
00281 }
00282 
00283 #endif // ABSTRACTUSEBUILDER_H
00284 

language/duchain

Skip menu "language/duchain"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDevelop Platform Libraries

Skip menu "KDevelop Platform Libraries"
  • interfaces
  • language
  •   codegen
  •   duchain
  •   editor
  • outputview
  • project
  • shell
  • sublime
  • util
  • vcs
Generated for KDevelop Platform Libraries by doxygen 1.5.9-20090814
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal