diff --git a/kdevplatform/language/duchain/builders/abstractusebuilder.h b/kdevplatform/language/duchain/builders/abstractusebuilder.h index 061d009109..a1210a6a8f 100644 --- a/kdevplatform/language/duchain/builders/abstractusebuilder.h +++ b/kdevplatform/language/duchain/builders/abstractusebuilder.h @@ -1,215 +1,215 @@ /* This file is part of KDevelop Copyright 2006-2008 Hamish Rodda This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_ABSTRACTUSEBUILDER_H #define KDEVPLATFORM_ABSTRACTUSEBUILDER_H #include "../declaration.h" #include "../use.h" #include "../topducontext.h" #include "../duchain.h" #include "../duchainlock.h" #include namespace KDevelop { /** * \short Abstract definition-use chain use builder class * * The AbstractUseBuilder is a convenience class template for creating customized * definition-use chain use builders from an AST. It simplifies creating or * modifying existing \ref Use "Uses" * * \author Hamish Rodda \ */ template class AbstractUseBuilder: public LanguageSpecificUseBuilderBase { public: /// Constructor. template AbstractUseBuilder(ParseSession* session) : LanguageSpecificUseBuilderBase(session), m_finishContext(true) { } AbstractUseBuilder() : m_finishContext(true) { } /** * Iterate an existing duchain, and add, remove or modify uses as determined * from the ast. * * \param node AST node to start visiting. */ void buildUses(T *node) { TopDUContext* top = dynamic_cast(this->contextFromNode(node)); if (top) { DUChainWriteLocker lock(DUChain::lock()); top->clearUsedDeclarationIndices(); if(top->features() & TopDUContext::AllDeclarationsContextsAndUses) LanguageSpecificUseBuilderBase::setRecompiling(true); } LanguageSpecificUseBuilderBase::supportBuild(node); } protected: struct ContextUseTracker { QVector createUses; }; /** * Register a new use at the AST node @p name. * * @param name AST node which both represents a use and the identifier for the declaration which is being used. */ void newUse(NameT* name) { QualifiedIdentifier id = this->identifierForNode(name); RangeInRevision newRange = this->editorFindRange(name, name); DUChainReadLocker lock(DUChain::lock()); QList declarations = LanguageSpecificUseBuilderBase::currentContext()->findDeclarations(id, newRange.start); foreach (Declaration* declaration, declarations) if (!declaration->isForwardDeclaration()) { declarations.clear(); declarations.append(declaration); break; } // If we don't break, there's no non-forward declaration lock.unlock(); - newUse( name, newRange, !declarations.isEmpty() ? DeclarationPointer(declarations.first()) : DeclarationPointer() ); + newUse( newRange, !declarations.isEmpty() ? DeclarationPointer(declarations.first()) : DeclarationPointer() ); } ///@todo Work this over! We must not pass around "Declaration*" values if the duchain is not locked. /** * Register a new use for a \a declaration with a \a node. * * \param node Node which encompasses the use. * \param declaration Declaration which is being used. May be null when a declaration cannot be found for the use. */ void newUse(T* node, const KDevelop::DeclarationPointer& declaration) { newUse(this->editorFindRange(node, node), declaration); } /** * Register a new use. * * \param newRange Text range which encompasses the use. * \param _declaration Declaration which is being used. May be null when a declaration cannot be found for the use. */ void newUse(const RangeInRevision& newRange, const DeclarationPointer& _declaration) { DUChainWriteLocker lock(DUChain::lock()); Declaration* declaration = _declaration.data(); if(!declaration) return; // The declaration was deleted in the meantime int declarationIndex = LanguageSpecificUseBuilderBase::currentContext()->topContext()->indexForUsedDeclaration(declaration); int contextUpSteps = 0; //We've got to use the stack here, and not parentContext(), because the order may be different { /* * We need to find a context that this use fits into, which must not necessarily be the current one. * The reason are macros like SOME_MACRO(SomeClass), where SomeClass is expanded to be within a * sub-context that comes from the macro. That sub-context will have a very small range, and will most * probably not be the range of the actual "SomeClass" text, so the "SomeClass" use has to be moved * into the context that surrounds the SOME_MACRO invocation. * */ DUContext* newContext = LanguageSpecificUseBuilderBase::currentContext(); while (!newContext->range().contains(newRange) && contextUpSteps < (LanguageSpecificUseBuilderBase::contextStack().size()-1)) { ++contextUpSteps; newContext = LanguageSpecificUseBuilderBase::contextStack()[LanguageSpecificUseBuilderBase::contextStack().size()-1-contextUpSteps]; } if (contextUpSteps) { m_finishContext = false; openContext(newContext); m_finishContext = true; currentUseTracker() = m_trackerStack.at(m_trackerStack.size()-contextUpSteps-2); } currentUseTracker().createUses << KDevelop::Use(newRange, declarationIndex); } if (contextUpSteps) { Q_ASSERT(m_contexts[m_trackerStack.size()-contextUpSteps-2] == LanguageSpecificUseBuilderBase::currentContext()); m_trackerStack[m_trackerStack.size()-contextUpSteps-2] = currentUseTracker(); m_finishContext = false; closeContext(); m_finishContext = true; } } /** * Reimplementation of openContext, to track which uses should be assigned to which context. */ virtual void openContext(KDevelop::DUContext* newContext) { LanguageSpecificUseBuilderBase::openContext(newContext); ContextUseTracker newTracker; m_trackerStack.push(newTracker); m_contexts.push(newContext); } /** * Reimplementation of closeContext, to track which uses should be assigned to which context. */ virtual void closeContext() { if(m_finishContext) { DUChainWriteLocker lock(DUChain::lock()); this->currentContext()->deleteUses(); ContextUseTracker& tracker(currentUseTracker()); for(int a = 0; a < tracker.createUses.size(); ++a) { this->currentContext()->createUse(tracker.createUses[a].m_declarationIndex, tracker.createUses[a].m_range); } } LanguageSpecificUseBuilderBase::closeContext(); m_trackerStack.pop(); m_contexts.pop(); } private: inline ContextUseTracker& currentUseTracker() { return m_trackerStack.top(); } Stack m_trackerStack; Stack m_contexts; //Whether not encountered uses should be deleted during closeContext() bool m_finishContext; }; } #endif // KDEVPLATFORM_ABSTRACTUSEBUILDER_H