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

language/duchain

abstractcontextbuilder.h

00001 /***************************************************************************
00002  *   This file is part of KDevelop                                         *
00003  *   Copyright 2008 Andreas Pakulat <apaku@gmx.de>                         *
00004  *   Copyright 2006 Roberto Raggi <roberto@kdevelop.org>                   *
00005  *   Copyright 2006-2008 Hamish Rodda <rodda@kde.org>                      *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU Library General Public License as       *
00009  *   published by the Free Software Foundation; either version 2 of the    *
00010  *   License, or (at your option) any later version.                       *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU Library General Public     *
00018  *   License along with this program; if not, write to the                 *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
00021  ***************************************************************************/
00022 
00023 #ifndef ABSTRACTABSTRACTCONTEXTBUILDER_H
00024 #define ABSTRACTABSTRACTCONTEXTBUILDER_H
00025 
00026 #include <climits>
00027 
00028 #include <QtCore/QMutexLocker>
00029 
00030 #include <ktexteditor/smartinterface.h>
00031 #include <ktexteditor/range.h>
00032 #include <ktexteditor/smartrange.h>
00033 #include <ktexteditor/document.h>
00034 
00035 #include "../../editor/editorintegrator.h"
00036 #include "../topducontext.h"
00037 #include "../duchainpointer.h"
00038 #include "../duchainlock.h"
00039 #include "../duchain.h"
00040 #include "../ducontext.h"
00041 #include "../identifier.h"
00042 #include "../indexedstring.h"
00043 #include "../parsingenvironment.h"
00044 #include "../smartconverter.h"
00045 
00046 namespace KDevelop
00047 {
00061 template<typename T, typename NameT>
00062 class AbstractContextBuilder
00063 {
00064 public:
00066   AbstractContextBuilder()
00067     : m_editor( 0 )
00068     , m_ownsEditorIntegrator(false)
00069     , m_compilingContexts( false )
00070     , m_recompiling( false )
00071     , m_lastContext( 0 )
00072   {
00073   }
00074 
00076   virtual ~AbstractContextBuilder()
00077   {
00078     if (m_ownsEditorIntegrator)
00079       delete m_editor;
00080   }
00081 
00089   void setEditor(EditorIntegrator* editor, bool ownsEditorIntegrator)
00090   {
00091     m_editor = editor;
00092     m_ownsEditorIntegrator = ownsEditorIntegrator;
00093   }
00094 
00107   virtual ReferencedTopDUContext build( const IndexedString& url, T* node,
00108                               ReferencedTopDUContext updateContext
00109                                     = ReferencedTopDUContext(), bool useSmart = true )
00110   {
00111     m_compilingContexts = true;
00112     m_editor->setCurrentUrl( url, useSmart );
00113 
00114     ReferencedTopDUContext top;
00115     {
00116       DUChainWriteLocker lock( DUChain::lock() );
00117       top = updateContext.data();
00118 
00119       if( top && top->smartRange() )
00120       {
00121         if( top && top->smartRange()->parentRange() )
00122         {
00123           //somethings wrong, a top level range can't have a parent
00124           Q_ASSERT(false);
00125         }
00126       }
00127       if( top )
00128       {
00129 //         kDebug() << "re-compiling";
00130         m_recompiling = true;
00131         if( m_compilingContexts )
00132         {
00133           LockedSmartInterface iface = m_editor->smart();
00134           if( iface && top->range().textRange() != iface.currentDocument()->documentRange() )
00135           {
00136             //Happens if the context wasn't smart
00137             top->setRange( SimpleRange( iface.currentDocument()->documentRange() ) );
00138           }
00139         }
00140       }else
00141       {
00142 //         kDebug() << "compiling";
00143         LockedSmartInterface iface = m_editor->smart();
00144         top = newTopContext( iface.currentDocument()
00145                                     ? SimpleRange( iface.currentDocument()->documentRange() )
00146                                     : SimpleRange( SimpleCursor( 0, 0 ), SimpleCursor( INT_MAX, INT_MAX ) ) );
00147         top->setSmartRange( m_editor->topRange( iface, EditorIntegrator::DefinitionUseChain ), DocumentRangeObject::Own );
00148         top->setType( DUContext::Global );
00149         DUChain::self()->addDocumentChain( top );
00150       }
00151       setEncountered( top );
00152       setContextOnNode( node, top );
00153     }
00154 
00155     supportBuild( node, top );
00156 
00157     {
00158       LockedSmartInterface iface = m_editor->smart();
00159       if( iface && top->range().textRange() != iface.currentDocument()->documentRange() )
00160       {
00161         kDebug() << "WARNING: top level context has wrong size:" << top->range().textRange() << "should be:" << iface.currentDocument()->documentRange();
00162         top->setRange( iface.currentDocument()->documentRange() );
00163       }
00164     }
00165     {
00166       /*DUChainReadLocker lock( DUChain::lock() );
00167       //foreach(DUContext* context, topLevelContext->childContexts());
00168       kDebug() << "built top-level context with" << top->localDeclarations().count() << "declarations," << top->localDeclarations().count() << " Definitions and" << top->childContexts().size() << "Child-Contexts";
00169 
00170       foreach( DUContext* contexts, top->childContexts() )
00171       {
00172         kDebug() << "CHILD:" << contexts->scopeIdentifier( true ) << "Parent:" << ( dynamic_cast<TopDUContext*>( contexts->parentContext() ) ? "top-context" : "" );
00173       }*/
00174     }
00175     m_compilingContexts = false;
00176     return top;
00177   }
00178 
00179 protected:
00184   virtual void supportBuild( T* node, DUContext* context = 0 )
00185   {
00186     if (!context)
00187       context = contextFromNode(node);
00188 
00189     openContext( context );
00190 
00191     //The url must be set before supportBuild is called, together with the decision
00192     //whether smart-ranges shold be created
00193     if(m_editor->currentUrl() != currentContext()->url())
00194       m_editor->setCurrentUrl(currentContext()->url(), true);
00195 
00196     {
00197       LockedSmartInterface iface = m_editor->smart();
00198       m_editor->setCurrentRange(iface, currentContext()->smartRange());
00199     }
00200 
00201     startVisiting(node);
00202 
00203     closeContext();
00204 
00205     Q_ASSERT(m_contextStack.isEmpty());
00206   }
00207 
00213   virtual void startVisiting( T* node ) = 0;
00214 
00222   virtual void setContextOnNode( T* node, DUContext* context ) = 0;
00223 
00231   virtual DUContext* contextFromNode( T* node ) = 0;
00232 
00244   virtual KTextEditor::Range editorFindRange( T* fromNode, T* toNode ) = 0;
00245 
00257   virtual KTextEditor::Range editorFindRangeForContext( T* fromNode, T* toNode )
00258   {
00259     return editorFindRange(fromNode, toNode);
00260   }
00261 
00268   virtual QualifiedIdentifier identifierForNode( NameT* node ) = 0;
00269 
00279   virtual DUContext* newContext(const SimpleRange& range)
00280   {
00281     return new DUContext(range, currentContext());
00282   }
00283 
00292   virtual TopDUContext* newTopContext(const SimpleRange& range, ParsingEnvironmentFile* file = 0)
00293   {
00294     return new TopDUContext(m_editor->currentUrl(), range, file);
00295   }
00296 
00298   inline DUContext* currentContext() const { return m_contextStack.top(); }
00300   inline DUContext* lastContext() const { return m_lastContext; }
00302   inline void clearLastContext() { m_lastContext = 0; }
00303 
00304   inline void setLastContext(DUContext* context) { m_lastContext = context; }
00305 
00312   inline bool recompiling() const { return m_recompiling; }
00313 
00320   inline void setRecompiling(bool recomp) { m_recompiling = recomp; }
00321 
00334   inline bool compilingContexts() const { return m_compilingContexts; }
00335 
00341   inline void setCompilingContexts(bool compilingContexts) { m_compilingContexts = compilingContexts; }
00342 
00351   DUContext* buildSubContexts( const KUrl& url, T *node,
00352                                          DUContext* parent )
00353   {
00354   //     m_compilingContexts = true;
00355   //     m_recompiling = false;
00356       {
00357         DUChainReadLocker lock( DUChain::lock() );
00358         m_editor->setCurrentUrl( IndexedString( url.pathOrUrl() ), (bool)parent->smartRange() );
00359       }
00360       setContextOnNode( node, parent );
00361       {
00362           openContext( contextFromNode( node ) );
00363           {
00364             LockedSmartInterface iface = m_editor->smart();
00365             m_editor->setCurrentRange( iface, m_editor->topRange( iface, EditorIntegrator::DefinitionUseChain ) );
00366           }
00367           startVisiting( node );
00368           closeContext();
00369       }
00370 
00371       m_compilingContexts = false;
00372 
00373       if ( contextFromNode( node ) == parent )
00374       {
00375           kDebug() << "Error in AbstractContextBuilder::buildSubContexts(...): du-context was not replaced with new one";
00376           DUChainWriteLocker lock( DUChain::lock() );
00377           deleteContextOnNode( node );
00378       }
00379 
00380       return contextFromNode( node );
00381   }
00382 
00389   void deleteContextOnNode( T* node )
00390   {
00391     delete contextFromNode( node );
00392     setContextOnNode( node, 0 );
00393   }
00394 
00403   DUContext* openContext( T* rangeNode, DUContext::ContextType type, NameT* identifier = 0)
00404   {
00405     if ( m_compilingContexts )
00406     {
00407 #ifdef DEBUG_UPDATE_MATCHING
00408     //kDebug() << "opening context with text" << editor()->tokensToStrings( rangeNode->start_token, rangeNode->end_token );
00409 #endif
00410       DUContext* ret = openContextInternal( editorFindRangeForContext( rangeNode, rangeNode ), type, identifier ? identifierForNode( identifier ) : QualifiedIdentifier() );
00411       setContextOnNode( rangeNode, ret );
00412       return ret;
00413     }
00414     else
00415     {
00416       openContext( contextFromNode(rangeNode) );
00417       {
00418         LockedSmartInterface iface = editor()->smart();
00419         editor()->setCurrentRange(iface, currentContext()->smartRange());
00420       }
00421       return currentContext();
00422     }
00423   }
00424 
00434   DUContext* openContext(T* node, const KDevelop::SimpleRange& range, DUContext::ContextType type, NameT* identifier = 0)
00435   {
00436     if (m_compilingContexts) {
00437 #ifdef DEBUG_UPDATE_MATCHING
00438       kDebug() << "opening custom context";
00439 #endif
00440       DUContext* ret = openContextInternal(range, type, identifier ? identifierForNode(identifier) : QualifiedIdentifier());
00441       setContextOnNode( node, ret );
00442       return ret;
00443 
00444     } else {
00445       openContext( contextFromNode(node) );
00446       {
00447         LockedSmartInterface iface = editor()->smart();
00448         editor()->setCurrentRange(iface, currentContext()->smartRange());
00449       }
00450       return currentContext();
00451     }
00452   }
00453 
00463   DUContext* openContext(T* node, const KDevelop::SimpleRange& range, DUContext::ContextType type, QualifiedIdentifier id)
00464   {
00465     if (m_compilingContexts) {
00466 #ifdef DEBUG_UPDATE_MATCHING
00467       kDebug() << "opening custom context";
00468 #endif
00469       DUContext* ret = openContextInternal(range, type, id);
00470       setContextOnNode( node, ret );
00471       return ret;
00472 
00473     } else {
00474       openContext( contextFromNode(node) );
00475       {
00476         LockedSmartInterface iface = editor()->smart();
00477         editor()->setCurrentRange(iface, currentContext()->smartRange());
00478       }
00479       return currentContext();
00480     }
00481   }
00482 
00491   DUContext* openContext( T* rangeNode, DUContext::ContextType type, const QualifiedIdentifier& identifier )
00492   {
00493     if ( m_compilingContexts )
00494     {
00495 #ifdef DEBUG_UPDATE_MATCHING
00496     //kDebug() << "opening context with text" << editor()->tokensToStrings( rangeNode->start_token, rangeNode->end_token );
00497 #endif
00498       DUContext* ret = openContextInternal( editorFindRangeForContext( rangeNode, rangeNode ), type, identifier );
00499       setContextOnNode( rangeNode, ret );
00500       return ret;
00501     }
00502     else
00503     {
00504       //kDebug() << "Opening Context associated with node";
00505       openContext( contextFromNode(rangeNode) );
00506       {
00507         LockedSmartInterface iface = editor()->smart();
00508         editor()->setCurrentRange(iface, currentContext()->smartRange());
00509       }
00510       return currentContext();
00511     }
00512   }
00513 
00523   DUContext* openContext( T* fromRange, T* toRange, DUContext::ContextType type, const QualifiedIdentifier& identifier = QualifiedIdentifier() )
00524   {
00525     if ( m_compilingContexts )
00526     {
00527 #ifdef DEBUG_UPDATE_MATCHING
00528       //kDebug() << "opening context with text" << editor()->tokensToStrings( fromRange->start_token, toRange->end_token );
00529 #endif
00530       DUContext* ret = openContextInternal( editorFindRangeForContext( fromRange, toRange ), type, identifier );
00531       setContextOnNode( fromRange, ret );
00532       return ret;
00533     }
00534     else
00535     {
00536       openContext( contextFromNode(fromRange) );
00537       {
00538         LockedSmartInterface iface = editor()->smart();
00539         editor()->setCurrentRange(iface, currentContext()->smartRange());
00540       }
00541       return currentContext();
00542     }
00543   }
00544 
00556   virtual void openContext( DUContext* newContext )
00557   {
00558     m_contextStack.push( newContext );
00559     m_nextContextStack.push( 0 );
00560   }
00561 
00566   void injectContext( const LockedSmartInterface& iface, DUContext* ctx, KTextEditor::SmartRange* range = 0 ) {
00567     openContext( ctx );
00568     m_editor->setCurrentRange( iface, range ? range : ctx->smartRange() );
00569   }
00570 
00574   void closeInjectedContext(const LockedSmartInterface& iface) {
00575     m_contextStack.pop();
00576     m_nextContextStack.pop();
00577     if(m_editor->smart())
00578       m_editor->exitCurrentRange(iface);
00579   }
00580 
00586   virtual void closeContext()
00587   {
00588     {
00589       DUChainWriteLocker lock( DUChain::lock() );
00590       //Remove all slaves that were not encountered while parsing
00591       if(m_compilingContexts)
00592         currentContext()->cleanIfNotEncountered( m_encountered );
00593       setEncountered( currentContext() );
00594 
00595       m_lastContext = currentContext();
00596     }
00597 
00598     m_contextStack.pop();
00599     m_nextContextStack.pop();
00600     if(LockedSmartInterface iface = m_editor->smart())
00601       m_editor->exitCurrentRange(iface);
00602   }
00603 
00610   void setEncountered( DUChainBase* item )
00611   {
00612     m_encountered.insert( item );
00613   }
00614 
00620   bool wasEncountered( DUChainBase* item )
00621   {
00622     return m_encountered.contains( item );
00623   }
00624 
00630   void setIdentifier( const QString& id )
00631   {
00632     m_identifier = Identifier( id );
00633     m_qIdentifier.push( m_identifier );
00634   }
00635 
00640   QualifiedIdentifier qualifiedIdentifier() const
00641   {
00642     return m_qIdentifier;
00643   }
00644 
00648   void clearQualifiedIdentifier()
00649   {
00650     m_qIdentifier.clear();
00651   }
00652 
00658   EditorIntegrator* editor() const
00659   {
00660     return m_editor;
00661   }
00662 
00670   const QStack<DUContext*>& contextStack() const
00671   {
00672     return m_contextStack;
00673   }
00674 
00681   int& nextContextIndex()
00682   {
00683     return m_nextContextStack.top();
00684   }
00685 
00695   virtual DUContext* openContextInternal( const SimpleRange& range, DUContext::ContextType type, const QualifiedIdentifier& identifier )
00696   {
00697     Q_ASSERT( m_compilingContexts );
00698     DUContext* ret = 0L;
00699     if(range.start > range.end)
00700     {
00701       kDebug() << "Bad context-range" << range.textRange();
00702     }
00703 
00704     {
00705       if ( recompiling() )
00706       {
00707         DUChainReadLocker readLock( DUChain::lock() );
00708         const QVector<DUContext*>& childContexts = currentContext()->childContexts();
00709 
00710         LockedSmartInterface iface = m_editor->smart();
00711         // translated is now in sync with the current state of the document, with whatever changes
00712         // have occurred since the text was fetched.
00713         SimpleRange translated = m_editor->translate(iface, range);
00714 
00715 //         if(iface)
00716 //           kDebug() << "translated by" << (translated.start.textCursor() - range.start.textCursor()) << (translated.end.textCursor() - range.end.textCursor()) << "to revision" << iface->currentRevision();
00717 
00718         int currentIndex = nextContextIndex();
00719         int lookingAhead = 0;
00720 
00721         for ( ; currentIndex < childContexts.count(); ++currentIndex )
00722         {
00723           DUContext* child = childContexts.at( currentIndex );
00724 
00725 //           if ( child->range().start > translated.end && child->smartRange() ) {
00726 // #ifdef DEBUG_UPDATE_MATCHING
00727 //               kDebug() << "While searching" << identifier << translated.textRange() << "(from" << range.textRange() << ") stopping because found" << child->localScopeIdentifier() << child->range().textRange();
00728 // #endif
00729 //               break;
00730 //           }
00731 
00732       //For unnamed child-ranges, we still do range-comparison, because we cannot distinguish them in other ways
00733           if ( child->type() == type && child->localScopeIdentifier() == identifier && (!identifier.isEmpty() || child->range() == translated) )
00734           {
00735             if(child->range() != translated && child->smartRange()) {
00736               kDebug() << "range mismatch while updating context. Range:" << child->range().textRange() << "should be:" << translated.textRange();
00737               break;
00738             }
00739             // No need to have the translated range accurate any more
00740             // Also we can't unlock after the duchain lock is unlocked
00741             iface.unlock();
00742 
00743             // Match
00744             ret = child;
00745             readLock.unlock();
00746             DUChainWriteLocker writeLock( DUChain::lock() );
00747 
00748             ret->clearImportedParentContexts();
00749             m_editor->setCurrentRange( iface, ret->smartRange() );
00750             ++currentIndex;
00751             break;
00752           }else{
00753 #ifdef DEBUG_UPDATE_MATCHING
00754           if(child->type() != type)
00755             kDebug() << "type mismatch" << child->type() << type;
00756           if(child->localScopeIdentifier() != identifier)
00757             kDebug() << "identifier mismatch" << child->localScopeIdentifier() << identifier;
00758           if(translated != child->range())
00759             kDebug() << "range mismatch" << child->range().textRange() << translated.textRange();
00760 
00761             kDebug() << "skipping range" << childContexts.at(currentIndex)->localScopeIdentifier() << childContexts.at(currentIndex)->range().textRange();
00762 #endif
00763           if ( child->range().start > translated.end && child->smartRange() && (currentIndex+1 == childContexts.count() || (childContexts.at(currentIndex+1)->localScopeIdentifier() != identifier || childContexts.at(currentIndex+1)->type() != type)) ) {
00764             ++lookingAhead;
00765             const int maxLookahead = 5;
00766             if(lookingAhead > maxLookahead)
00767               break; //Don't move the currentIndex too far
00768           }
00769           }
00770         }
00771         if(ret)
00772           nextContextIndex() = currentIndex; //If we had a match, jump forward to that position
00773         else
00774           ++nextContextIndex();   //If we did not have a match, just increment by 1
00775       }
00776 
00777       if ( !ret )
00778       {
00779         DUChainWriteLocker writeLock( DUChain::lock() );
00780 
00781         ret = newContext( SimpleRange( range ) );
00782         {
00783           LockedSmartInterface iface = m_editor->smart();
00784           ret->setSmartRange( m_editor->createRange( iface, range.textRange() ), DocumentRangeObject::Own );
00785         }
00786         ret->setType( type );
00787 
00788         if (!identifier.isEmpty())
00789           ret->setLocalScopeIdentifier(identifier);
00790 
00791         setInSymbolTable(ret);
00792 
00793 //         if( recompiling() )
00794 //           kDebug() << "created new context while recompiling for " << identifier.toString() << "(" << ret->range().textRange() << ")";
00795       }
00796     }
00797 
00798     m_encountered.insert( ret );
00799     openContext( ret );
00800     return ret;
00801   }
00802 
00804   virtual void setInSymbolTable(DUContext* context) {
00805     if(!context->parentContext()->inSymbolTable()) {
00806       context->setInSymbolTable(false);
00807       return;
00808     }
00809     DUContext::ContextType type = context->type();
00810     context->setInSymbolTable(type == DUContext::Class || type == DUContext::Namespace || type == DUContext::Global || type == DUContext::Helper || type == DUContext::Enum);
00811   }
00812 
00813 private:
00814 
00815   Identifier m_identifier;
00816   QualifiedIdentifier m_qIdentifier;
00817   EditorIntegrator* m_editor;
00818   bool m_ownsEditorIntegrator: 1;
00819   bool m_compilingContexts : 1;
00820   bool m_recompiling : 1;
00821   QStack<int> m_nextContextStack;
00822   DUContext* m_lastContext;
00823   //Here all valid declarations/uses/... will be collected
00824   QSet<DUChainBase*> m_encountered;
00825   QStack<DUContext*> m_contextStack;
00826 };
00827 
00828 }
00829 
00830 #endif

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