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"
25 #include <ktexteditor/smartrange.h>
26 #include <ktexteditor/document.h>
30 #include "topducontext.h"
31 #include "topducontextdynamicdata.h"
33 #include "forwarddeclaration.h"
35 #include "duchainlock.h"
36 #include "ducontextdata.h"
37 #include "declarationid.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
;
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
;
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
);
85 void Declaration::setKind(Kind kind
) {
86 DUCHAIN_D_DYNAMIC(Declaration
);
90 bool Declaration::inDUChain() const {
91 DUCHAIN_D(Declaration
);
92 if( d
->m_anonymousInContext
)
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);
106 m_indexInTopContext
= 0;
112 uint
Declaration::ownIndex() const
115 return m_indexInTopContext
;
118 Declaration::Declaration(const Declaration
& rhs
)
119 : DUChainBase(*new DeclarationData( *rhs
.d_func() )) {
120 setSmartRange(rhs
.smartRange(), DocumentRangeObject::DontOwn
);
123 m_indexInTopContext
= 0;
126 Declaration::Declaration( DeclarationData
& dd
) : DUChainBase(dd
)
130 m_indexInTopContext
= 0;
133 Declaration::Declaration( DeclarationData
& dd
, const SimpleRange
& range
)
134 : DUChainBase(dd
, range
)
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));
169 setAbstractType(AbstractType::Ptr());
170 //DUChain::declarationChanged(this, DUChainObserver::Deletion, DUChainObserver::NotApplicable);
173 QByteArray
Declaration::comment() const {
174 DUCHAIN_D(Declaration
);
178 return Repositories::arrayFromItem(commentRepository
.itemFromIndex(d
->m_comment
));
181 void Declaration::setComment(const QByteArray
& str
) {
182 DUCHAIN_D_DYNAMIC(Declaration
);
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
) {
207 m_declarationIndex
= 0;
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
);
222 bool LocalIndexedDeclaration::isLoaded(TopDUContext
* top
) const {
223 if(m_declarationIndex
)
224 return top
->m_dynamicData
->isDeclarationForIndexLoaded(m_declarationIndex
);
229 IndexedDeclaration::IndexedDeclaration(uint topContext
, uint declarationIndex
) : m_topContext(topContext
), m_declarationIndex(declarationIndex
) {
232 IndexedDeclaration::IndexedDeclaration(Declaration
* decl
) {
234 m_topContext
= decl
->topContext()->ownIndex();
235 m_declarationIndex
= decl
->m_indexInTopContext
;
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
)
251 TopDUContext
* ctx
= DUChain::self()->chainForIndex(m_topContext
);
255 return ctx
->m_dynamicData
->getDeclarationForIndex(m_declarationIndex
);
258 void Declaration::rebuildDynamicData(DUContext
* parent
, uint ownIndex
)
260 DUChainBase::rebuildDynamicData(parent
, ownIndex
);
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
)
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
)
300 DUCHAIN_D_DYNAMIC(Declaration
);
303 //DUChain::declarationChanged(this, DUChainObserver::Removal, DUChainObserver::DataType);
305 d
->m_type
= type
->indexed();
308 //DUChain::declarationChanged(this, DUChainObserver::Addition, DUChainObserver::DataType);
311 Declaration
* Declaration::specialize(uint
/*specialization*/, const TopDUContext
* /*topContext*/, int /*upDistance*/)
316 QualifiedIdentifier
Declaration::qualifiedIdentifier() const
320 QualifiedIdentifier ret
;
321 DUContext
* ctx
= m_context
;
323 ret
= ctx
->scopeIdentifier(true);
324 ret
.push(d_func()->m_identifier
);
328 // QString Declaration::mangledIdentifier() const
330 // //GNU mangling specs from http://theory.uwinnipeg.ca/gnu/gcc/gxxint_15.html
332 // if (abstractType())
333 // return abstractType()->mangled();
336 // return qualifiedIdentifier().mangled();
339 DUContext
* Declaration::context() const
341 //ENSURE_CAN_READ Commented out for performance reasons
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()) {
353 setInSymbolTable(false);
355 //We don't need to clear, because it's not allowed to move from one top-context into another
359 DUCHAIN_D_DYNAMIC(Declaration
);
360 if (m_context
&& context
) {
361 Q_ASSERT(m_context
->topContext() == context
->topContext());
365 if( !d
->m_anonymousInContext
) {
366 m_context
->m_dynamicData
->removeDeclaration(this);
367 //DUChain::declarationChanged(this, DUChainObserver::Removal, DUChainObserver::Context, m_context);
372 m_topContext
= context
->topContext();
376 d
->m_anonymousInContext
= anonymous
;
380 if(!m_indexInTopContext
)
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
)
398 if(!context() || (!context()->isAnonymous() && !d_func()->m_anonymousInContext
)) {
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)) {
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 {
424 if(isForwardDeclaration()) {
425 const ForwardDeclaration
* dec
= toForwardDeclaration();
426 Declaration
* ret
= dec
->resolve(topContext
);
433 Declaration
* Declaration::logicalDeclaration(const TopDUContext
* topContext
) {
435 if(isForwardDeclaration()) {
436 ForwardDeclaration
* dec
= toForwardDeclaration();
437 Declaration
* ret
= dec
->resolve(topContext
);
444 DUContext
* Declaration::logicalInternalContext(const TopDUContext
* topContext
) const {
447 if(!isDefinition()) {
448 Declaration
* def
= FunctionDefinition::definition(this);
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
467 return d_func()->m_internalContext
.context();
470 void Declaration::setInternalContext(DUContext
* context
)
472 if(this->context()) {
475 DUCHAIN_D_DYNAMIC(Declaration
);
477 if( context
== d
->m_internalContext
.context() )
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();
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);
496 context
->setOwner(this);
500 bool Declaration::operator ==(const Declaration
& other
) const
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
517 DUCHAIN_D(Declaration
);
519 return d
->m_isDefinition
;
522 void Declaration::setDeclarationIsDefinition(bool dd
)
525 DUCHAIN_D_DYNAMIC(Declaration
);
526 d
->m_isDefinition
= dd
;
527 // if (d->m_isDefinition && definition()) {
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 {
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
559 if(inSymbolTable() && !forceDirect
)
560 return DeclarationId(qualifiedIdentifier(), additionalIdentity(), specialization());
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
);
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
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;
645 bool Declaration::isForwardDeclaration() const
650 bool Declaration::isFunctionDeclaration() const
655 uint
Declaration::additionalIdentity() const
660 bool Declaration::equalQualifiedIdentifier(const Declaration
* rhs
) const {
662 DUCHAIN_D(Declaration
);
663 if(d
->m_identifier
!= rhs
->d_func()->m_identifier
)
666 return m_context
->equalScopeIdentifier(m_context
);
669 QList
<KTextEditor::SmartRange
*> Declaration::smartUses() const
671 Q_ASSERT(topContext());
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())
685 TopDUContext
* context
= indexedContext
.data();
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
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();
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
)
732 // kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on