00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00124 Q_ASSERT(false);
00125 }
00126 }
00127 if( top )
00128 {
00129
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
00137 top->setRange( SimpleRange( iface.currentDocument()->documentRange() ) );
00138 }
00139 }
00140 }else
00141 {
00142
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
00167
00168
00169
00170
00171
00172
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
00192
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
00355
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
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
00497 #endif
00498 DUContext* ret = openContextInternal( editorFindRangeForContext( rangeNode, rangeNode ), type, identifier );
00499 setContextOnNode( rangeNode, ret );
00500 return ret;
00501 }
00502 else
00503 {
00504
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
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
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
00712
00713 SimpleRange translated = m_editor->translate(iface, range);
00714
00715
00716
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
00726
00727
00728
00729
00730
00731
00732
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
00740
00741 iface.unlock();
00742
00743
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;
00768 }
00769 }
00770 }
00771 if(ret)
00772 nextContextIndex() = currentIndex;
00773 else
00774 ++nextContextIndex();
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
00794
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
00824 QSet<DUChainBase*> m_encountered;
00825 QStack<DUContext*> m_contextStack;
00826 };
00827
00828 }
00829
00830 #endif