Add AbstractDeclarationNavigationContext, and move the html-method from
[kdevelopdvcssupport.git] / language / duchain / declaration.cpp
blobe13e4bebd54b7afe6569f7ad578741991b91e1cb
1 /* This file is part of KDevelop
2 Copyright 2006 Hamish Rodda <rodda@kde.org>
3 Copyright 2007 2008 David Nolden <david.nolden.kdevelop@art-master.de>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include "declaration.h"
21 #include "declarationdata.h"
23 #include <QByteArray>
25 #include <ktexteditor/smartrange.h>
26 #include <ktexteditor/document.h>
28 #include <limits>
30 #include "topducontext.h"
31 #include "topducontextdynamicdata.h"
32 #include "use.h"
33 #include "forwarddeclaration.h"
34 #include "duchain.h"
35 #include "duchainlock.h"
36 #include "ducontextdata.h"
37 #include "declarationid.h"
38 #include "uses.h"
39 #include "indexedstring.h"
40 #include "duchainregister.h"
41 #include "persistentsymboltable.h"
42 #include "repositories/stringrepository.h"
43 #include "types/identifiedtype.h"
44 #include "types/structuretype.h"
45 #include "functiondefinition.h"
46 #include "codemodel.h"
47 #include "functiondefinition.h"
48 #include "specializationstore.h"
50 using namespace KTextEditor;
52 namespace KDevelop
55 Repositories::StringRepository commentRepository("Comment Repository");
57 REGISTER_DUCHAIN_ITEM(Declaration);
59 DeclarationData::DeclarationData()
60 : m_comment(0), m_isDefinition(false), m_inSymbolTable(false),
61 m_isTypeAlias(false), m_anonymousInContext(false)
63 m_kind = Declaration::Instance;
66 DeclarationData::DeclarationData( const DeclarationData& rhs ) : DUChainBaseData(rhs)
68 m_identifier = rhs.m_identifier;
69 m_declaration = rhs.m_declaration;
70 m_type = rhs.m_type;
71 m_kind = rhs.m_kind;
72 m_isDefinition = rhs.m_isDefinition;
73 m_isTypeAlias = rhs.m_isTypeAlias;
74 m_inSymbolTable = rhs.m_inSymbolTable;
75 m_comment = rhs.m_comment;
76 m_anonymousInContext = rhs.m_anonymousInContext;
77 m_internalContext = rhs.m_internalContext;
80 Declaration::Kind Declaration::kind() const {
81 DUCHAIN_D(Declaration);
82 return d->m_kind;
85 void Declaration::setKind(Kind kind) {
86 DUCHAIN_D_DYNAMIC(Declaration);
87 d->m_kind = kind;
90 bool Declaration::inDUChain() const {
91 DUCHAIN_D(Declaration);
92 if( d->m_anonymousInContext )
93 return false;
94 if( !context() )
95 return false;
96 TopDUContext* top = topContext();
97 return top && top->inDuChain();
100 Declaration::Declaration( const SimpleRange& range, DUContext* context )
101 : DUChainBase(*new DeclarationData, range)
103 d_func_dynamic()->setClassId(this);
104 m_topContext = 0;
105 m_context = 0;
106 m_indexInTopContext = 0;
108 if(context)
109 setContext(context);
112 uint Declaration::ownIndex() const
114 ENSURE_CAN_READ
115 return m_indexInTopContext;
118 Declaration::Declaration(const Declaration& rhs)
119 : DUChainBase(*new DeclarationData( *rhs.d_func() )) {
120 setSmartRange(rhs.smartRange(), DocumentRangeObject::DontOwn);
121 m_topContext = 0;
122 m_context = 0;
123 m_indexInTopContext = 0;
126 Declaration::Declaration( DeclarationData & dd ) : DUChainBase(dd)
128 m_topContext = 0;
129 m_context = 0;
130 m_indexInTopContext = 0;
133 Declaration::Declaration( DeclarationData & dd, const SimpleRange& range )
134 : DUChainBase(dd, range)
136 m_topContext = 0;
137 m_context = 0;
138 m_indexInTopContext = 0;
141 Declaration::~Declaration()
143 DUCHAIN_D_DYNAMIC(Declaration);
144 // Inserted by the builder after construction has finished.
145 if(!topContext()->deleting() || !topContext()->isOnDisk()) {
146 if( d->m_internalContext.context() )
147 d->m_internalContext.context()->setOwner(0);
150 if (d->m_inSymbolTable && !d->m_identifier.isEmpty()) {
151 if(!topContext()->deleting() || !topContext()->isOnDisk()) {
152 QualifiedIdentifier id = qualifiedIdentifier();
153 PersistentSymbolTable::self().removeDeclaration(id, this);
154 CodeModel::self().removeItem(url(), id);
158 d->m_inSymbolTable = false;
160 // context is only null in the test cases
161 if (context() && !d->m_anonymousInContext) {
162 Q_ASSERT(context()->m_dynamicData->removeDeclaration(this));
165 clearOwnIndex();
167 setContext(0);
169 setAbstractType(AbstractType::Ptr());
170 //DUChain::declarationChanged(this, DUChainObserver::Deletion, DUChainObserver::NotApplicable);
173 QByteArray Declaration::comment() const {
174 DUCHAIN_D(Declaration);
175 if(!d->m_comment)
176 return 0;
177 else
178 return Repositories::arrayFromItem(commentRepository.itemFromIndex(d->m_comment));
181 void Declaration::setComment(const QByteArray& str) {
182 DUCHAIN_D_DYNAMIC(Declaration);
183 if(str.isEmpty())
184 d->m_comment = 0;
185 else
186 d->m_comment = commentRepository.index(Repositories::StringRepositoryItemRequest(str, IndexedString::hashString(str, str.length()), str.length()));
189 void Declaration::setComment(const QString& str) {
190 setComment(str.toUtf8());
193 Identifier Declaration::identifier( ) const
195 //ENSURE_CAN_READ Commented out for performance reasons
196 return d_func()->m_identifier.identifier();
199 IndexedIdentifier Declaration::indexedIdentifier( ) const
201 //ENSURE_CAN_READ Commented out for performance reasons
202 return d_func()->m_identifier;
205 LocalIndexedDeclaration::LocalIndexedDeclaration(Declaration* decl) {
206 if(!decl)
207 m_declarationIndex = 0;
208 else
209 m_declarationIndex = decl->m_indexInTopContext;
212 LocalIndexedDeclaration::LocalIndexedDeclaration(uint declarationIndex) : m_declarationIndex(declarationIndex) {
215 Declaration* LocalIndexedDeclaration::data(TopDUContext* top) const {
216 if(m_declarationIndex)
217 return top->m_dynamicData->getDeclarationForIndex(m_declarationIndex);
218 else
219 return 0;
222 bool LocalIndexedDeclaration::isLoaded(TopDUContext* top) const {
223 if(m_declarationIndex)
224 return top->m_dynamicData->isDeclarationForIndexLoaded(m_declarationIndex);
225 else
226 return false;
229 IndexedDeclaration::IndexedDeclaration(uint topContext, uint declarationIndex) : m_topContext(topContext), m_declarationIndex(declarationIndex) {
232 IndexedDeclaration::IndexedDeclaration(Declaration* decl) {
233 if(decl) {
234 m_topContext = decl->topContext()->ownIndex();
235 m_declarationIndex = decl->m_indexInTopContext;
236 }else{
237 m_topContext = 0;
238 m_declarationIndex = 0;
242 IndexedTopDUContext IndexedDeclaration::indexedTopContext() const {
243 return IndexedTopDUContext(m_topContext);
246 Declaration* IndexedDeclaration::declaration() const {
247 ENSURE_CHAIN_READ_LOCKED
248 if(!m_topContext || !m_declarationIndex)
249 return 0;
251 TopDUContext* ctx = DUChain::self()->chainForIndex(m_topContext);
252 if(!ctx)
253 return 0;
255 return ctx->m_dynamicData->getDeclarationForIndex(m_declarationIndex);
258 void Declaration::rebuildDynamicData(DUContext* parent, uint ownIndex)
260 DUChainBase::rebuildDynamicData(parent, ownIndex);
262 m_context = parent;
263 m_topContext = parent->topContext();
264 m_indexInTopContext = ownIndex;
266 parent->m_dynamicData->addDeclarationToHash(d_func()->m_identifier.identifier(), this);
269 void Declaration::setIdentifier(const Identifier& identifier)
271 ENSURE_CAN_WRITE
272 DUCHAIN_D_DYNAMIC(Declaration);
273 bool wasInSymbolTable = d->m_inSymbolTable;
275 setInSymbolTable(false);
277 if( m_context && !d->m_anonymousInContext )
278 m_context->changingIdentifier( this, d->m_identifier, identifier );
280 d->m_identifier = identifier;
282 setInSymbolTable(wasInSymbolTable);
283 //DUChain::declarationChanged(this, DUChainObserver::Change, DUChainObserver::Identifier);
286 IndexedType Declaration::indexedType() const
288 return d_func()->m_type;
291 AbstractType::Ptr Declaration::abstractType( ) const
293 //ENSURE_CAN_READ Commented out for performance reasons
294 return d_func()->m_type.type();
297 void Declaration::setAbstractType(AbstractType::Ptr type)
299 ENSURE_CAN_WRITE
300 DUCHAIN_D_DYNAMIC(Declaration);
302 //if (d->m_type)
303 //DUChain::declarationChanged(this, DUChainObserver::Removal, DUChainObserver::DataType);
305 d->m_type = type->indexed();
307 //if (d->m_type)
308 //DUChain::declarationChanged(this, DUChainObserver::Addition, DUChainObserver::DataType);
311 Declaration* Declaration::specialize(uint /*specialization*/, const TopDUContext* /*topContext*/, int /*upDistance*/)
313 return this;
316 QualifiedIdentifier Declaration::qualifiedIdentifier() const
318 ENSURE_CAN_READ
320 QualifiedIdentifier ret;
321 DUContext* ctx = m_context;
322 if(ctx)
323 ret = ctx->scopeIdentifier(true);
324 ret.push(d_func()->m_identifier);
325 return ret;
328 // QString Declaration::mangledIdentifier() const
329 // {
330 // //GNU mangling specs from http://theory.uwinnipeg.ca/gnu/gcc/gxxint_15.html
332 // if (abstractType())
333 // return abstractType()->mangled();
335 // // Error...
336 // return qualifiedIdentifier().mangled();
337 // }
339 DUContext * Declaration::context() const
341 //ENSURE_CAN_READ Commented out for performance reasons
342 return m_context;
345 void Declaration::setContext(DUContext* context, bool anonymous)
347 Q_ASSERT(!context || context->topContext());
348 ///@todo re-enable. In C++ support we need a short window to put visible declarations into template contexts
349 if(!specialization()) {
350 ENSURE_CAN_WRITE
353 setInSymbolTable(false);
355 //We don't need to clear, because it's not allowed to move from one top-context into another
356 // clearOwnIndex();
359 DUCHAIN_D_DYNAMIC(Declaration);
360 if (m_context && context) {
361 Q_ASSERT(m_context->topContext() == context->topContext());
364 if (m_context) {
365 if( !d->m_anonymousInContext ) {
366 m_context->m_dynamicData->removeDeclaration(this);
367 //DUChain::declarationChanged(this, DUChainObserver::Removal, DUChainObserver::Context, m_context);
371 if(context)
372 m_topContext = context->topContext();
373 else
374 m_topContext = 0;
376 d->m_anonymousInContext = anonymous;
377 m_context = context;
379 if (context) {
380 if(!m_indexInTopContext)
381 allocateOwnIndex();
383 if(!d->m_anonymousInContext) {
384 context->m_dynamicData->addDeclaration(this);
385 //DUChain::declarationChanged(this, DUChainObserver::Addition, DUChainObserver::Context, m_context);
388 if(context->inSymbolTable() && !anonymous)
389 setInSymbolTable(true);
393 void Declaration::clearOwnIndex() {
395 if(!m_indexInTopContext)
396 return;
398 if(!context() || (!context()->isAnonymous() && !d_func()->m_anonymousInContext)) {
399 ENSURE_CAN_WRITE
402 if(m_indexInTopContext) {
403 Q_ASSERT(m_topContext);
404 m_topContext->m_dynamicData->clearDeclarationIndex(this);
406 m_indexInTopContext = 0;
409 void Declaration::allocateOwnIndex() {
411 ///@todo Fix multithreading stuff with template instantiation, preferably using some internal mutexes
412 // if(context() && (!context()->isAnonymous() && !d_func()->m_anonymousInContext)) {
413 // ENSURE_CAN_WRITE
414 // }
416 Q_ASSERT(m_topContext);
418 m_indexInTopContext = m_topContext->m_dynamicData->allocateDeclarationIndex(this, d_func()->m_anonymousInContext || !context() || context()->isAnonymous());
419 Q_ASSERT(m_indexInTopContext);
422 const Declaration* Declaration::logicalDeclaration(const TopDUContext* topContext) const {
423 ENSURE_CAN_READ
424 if(isForwardDeclaration()) {
425 const ForwardDeclaration* dec = toForwardDeclaration();
426 Declaration* ret = dec->resolve(topContext);
427 if(ret)
428 return ret;
430 return this;
433 Declaration* Declaration::logicalDeclaration(const TopDUContext* topContext) {
434 ENSURE_CAN_READ
435 if(isForwardDeclaration()) {
436 ForwardDeclaration* dec = toForwardDeclaration();
437 Declaration* ret = dec->resolve(topContext);
438 if(ret)
439 return ret;
441 return this;
444 DUContext * Declaration::logicalInternalContext(const TopDUContext* topContext) const {
445 ENSURE_CAN_READ
447 if(!isDefinition()) {
448 Declaration* def = FunctionDefinition::definition(this);
449 if( def )
450 return def->internalContext();
453 if( d_func()->m_isTypeAlias ) {
454 ///If this is a type-alias, return the internal context of the actual type.
455 AbstractType::Ptr t = abstractType();
456 IdentifiedType* idType = dynamic_cast<IdentifiedType*>(t.unsafeData());
457 if( idType && idType->declaration(topContext) && idType->declaration(topContext) != this )
458 return idType->declaration(topContext)->logicalInternalContext( topContext );
461 return internalContext();
464 DUContext * Declaration::internalContext() const
466 ENSURE_CAN_READ
467 return d_func()->m_internalContext.context();
470 void Declaration::setInternalContext(DUContext* context)
472 if(this->context()) {
473 ENSURE_CAN_WRITE
475 DUCHAIN_D_DYNAMIC(Declaration);
477 if( context == d->m_internalContext.context() )
478 return;
480 if(!m_topContext) {
481 //Take the top-context from the other side. We need to allocate an index, so we can safely call setOwner(..)
482 m_topContext = context->topContext();
483 allocateOwnIndex();
486 DUContext* oldInternalContext = d->m_internalContext.context();
488 d->m_internalContext = context;
490 //Q_ASSERT( !oldInternalContext || oldInternalContext->owner() == this );
491 if( oldInternalContext && oldInternalContext->owner() == this )
492 oldInternalContext->setOwner(0);
495 if( context )
496 context->setOwner(this);
500 bool Declaration::operator ==(const Declaration & other) const
502 ENSURE_CAN_READ
504 return this == &other;
507 QString Declaration::toString() const
509 return QString("%3 %4").arg(abstractType() ? abstractType()->toString() : QString("<notype>")).arg(identifier().toString());
512 // kate: indent-width 2;
514 bool Declaration::isDefinition() const
516 ENSURE_CAN_READ
517 DUCHAIN_D(Declaration);
519 return d->m_isDefinition;
522 void Declaration::setDeclarationIsDefinition(bool dd)
524 ENSURE_CAN_WRITE
525 DUCHAIN_D_DYNAMIC(Declaration);
526 d->m_isDefinition = dd;
527 // if (d->m_isDefinition && definition()) {
528 // setDefinition(0);
529 // }
532 ///@todo see whether it would be useful to create an own TypeAliasDeclaration sub-class for this
533 bool Declaration::isTypeAlias() const {
534 DUCHAIN_D(Declaration);
535 return d->m_isTypeAlias;
538 void Declaration::setIsTypeAlias(bool isTypeAlias) {
539 DUCHAIN_D_DYNAMIC(Declaration);
540 d->m_isTypeAlias = isTypeAlias;
543 uint Declaration::specialization() const {
544 return 0;
547 void Declaration::activateSpecialization()
549 if(specialization()) {
550 DeclarationId baseId(id());
551 baseId.setSpecialization(0);
552 SpecializationStore::self().set(baseId, specialization());
556 DeclarationId Declaration::id(bool forceDirect) const
558 ENSURE_CAN_READ
559 if(inSymbolTable() && !forceDirect)
560 return DeclarationId(qualifiedIdentifier(), additionalIdentity(), specialization());
561 else
562 return DeclarationId(IndexedDeclaration(const_cast<Declaration*>(this)), specialization());
565 bool Declaration::inSymbolTable() const
567 DUCHAIN_D(Declaration);
568 return d->m_inSymbolTable;
571 CodeModelItem::Kind kindForDeclaration(Declaration* decl) {
572 CodeModelItem::Kind kind = CodeModelItem::Unknown;
574 if(decl->isFunctionDeclaration()) {
575 kind = CodeModelItem::Function;
578 if(decl->kind() == Declaration::Type && decl->type<StructureType>())
579 kind = CodeModelItem::Class;
581 if(kind == CodeModelItem::Unknown && decl->kind() == Declaration::Instance)
582 kind = CodeModelItem::Variable;
584 if(decl->isForwardDeclaration())
585 kind = (CodeModelItem::Kind)(kind | CodeModelItem::ForwardDeclaration);
587 return kind;
590 void Declaration::updateCodeModel()
592 DUCHAIN_D(Declaration);
593 if(!d->m_identifier.isEmpty() && d->m_inSymbolTable) {
594 QualifiedIdentifier id(qualifiedIdentifier());
595 CodeModel::self().updateItem(url(), id, kindForDeclaration(this));
599 void Declaration::setInSymbolTable(bool inSymbolTable)
601 DUCHAIN_D_DYNAMIC(Declaration);
602 if(!d->m_identifier.isEmpty()) {
603 if(!d->m_inSymbolTable && inSymbolTable) {
604 QualifiedIdentifier id(qualifiedIdentifier());
605 PersistentSymbolTable::self().addDeclaration(id, this);
607 CodeModel::self().addItem(url(), id, kindForDeclaration(this));
610 else if(d->m_inSymbolTable && !inSymbolTable) {
611 QualifiedIdentifier id(qualifiedIdentifier());
612 PersistentSymbolTable::self().removeDeclaration(id, this);
614 CodeModel::self().removeItem(url(), id);
617 d->m_inSymbolTable = inSymbolTable;
620 ForwardDeclaration* Declaration::toForwardDeclaration()
622 return static_cast<ForwardDeclaration*>(this);
625 const ForwardDeclaration* Declaration::toForwardDeclaration() const
627 return static_cast<const ForwardDeclaration*>(this);
630 TopDUContext * Declaration::topContext() const
632 return m_topContext;
635 Declaration* Declaration::clonePrivate() const {
636 return new Declaration(*this);
639 Declaration* Declaration::clone() const {
640 Declaration* ret = clonePrivate();
641 ret->d_func_dynamic()->m_inSymbolTable = false;
642 return ret;
645 bool Declaration::isForwardDeclaration() const
647 return false;
650 bool Declaration::isFunctionDeclaration() const
652 return false;
655 uint Declaration::additionalIdentity() const
657 return 0;
660 bool Declaration::equalQualifiedIdentifier(const Declaration* rhs) const {
661 ENSURE_CAN_READ
662 DUCHAIN_D(Declaration);
663 if(d->m_identifier != rhs->d_func()->m_identifier)
664 return false;
666 return m_context->equalScopeIdentifier(m_context);
669 QList<KTextEditor::SmartRange*> Declaration::smartUses() const
671 Q_ASSERT(topContext());
672 ENSURE_CAN_READ
673 QSet<KTextEditor::SmartRange*> tempUses;
674 //First, search for uses within the own context
676 foreach(KTextEditor::SmartRange* range, allSmartUses(topContext(), const_cast<Declaration*>(this)))
677 tempUses.insert(range);
680 KDevVarLengthArray<IndexedTopDUContext> useContexts = DUChain::uses()->uses(id());
682 FOREACH_ARRAY(IndexedTopDUContext indexedContext, useContexts) {
683 if(!indexedContext.isLoaded())
684 continue;
685 TopDUContext* context = indexedContext.data();
686 if(context) {
687 foreach(KTextEditor::SmartRange* range, allSmartUses(context, const_cast<Declaration*>(this)))
688 tempUses.insert(range);
692 return tempUses.toList();
695 QMap<IndexedString, QList<SimpleRange> > Declaration::uses() const
697 ENSURE_CAN_READ
698 QMap<IndexedString, QMap<SimpleRange, bool> > tempUses;
700 //First, search for uses within the own context
702 QMap<SimpleRange, bool>& ranges(tempUses[topContext()->url()]);
703 foreach(const SimpleRange& range, allUses(topContext(), const_cast<Declaration*>(this)))
704 ranges[range] = true;
707 KDevVarLengthArray<IndexedTopDUContext> useContexts = DUChain::uses()->uses(id());
709 FOREACH_ARRAY(IndexedTopDUContext indexedContext, useContexts) {
710 TopDUContext* context = indexedContext.data();
711 if(context) {
712 QMap<SimpleRange, bool>& ranges(tempUses[context->url()]);
713 foreach(const SimpleRange& range, allUses(context, const_cast<Declaration*>(this)))
714 ranges[range] = true;
718 QMap<IndexedString, QList<SimpleRange> > ret;
720 for(QMap<IndexedString, QMap<SimpleRange, bool> >::const_iterator it = tempUses.begin(); it != tempUses.end(); ++it) {
721 if(!(*it).isEmpty()) {
722 QList<SimpleRange>& list(ret[it.key()]);
723 for(QMap<SimpleRange, bool>::const_iterator it2 = (*it).begin(); it2 != (*it).end(); ++it2)
724 list << it2.key();
727 return ret;
732 // kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on