4 * Copyright 2007 Hamish Rodda <rodda@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "duchainutils.h"
24 #include <kiconloader.h>
26 #include <interfaces/ilanguage.h>
27 #include <interfaces/icore.h>
28 #include <interfaces/ilanguagecontroller.h>
30 #include "../interfaces/ilanguagesupport.h"
32 #include "declaration.h"
33 #include "classfunctiondeclaration.h"
34 #include "ducontext.h"
37 #include "declaration.h"
38 #include "duchainlock.h"
39 #include "classmemberdeclaration.h"
40 #include "functiondefinition.h"
41 #include "specializationstore.h"
43 using namespace KDevelop
;
44 using namespace KTextEditor
;
46 CodeCompletionModel::CompletionProperties
DUChainUtils::completionProperties(Declaration
* dec
)
48 CodeCompletionModel::CompletionProperties p
;
50 if (ClassMemberDeclaration
* member
= dynamic_cast<ClassMemberDeclaration
*>(dec
)) {
51 switch (member
->accessPolicy()) {
52 case Declaration::Public
:
53 p
|= CodeCompletionModel::Public
;
55 case Declaration::Protected
:
56 p
|= CodeCompletionModel::Protected
;
58 case Declaration::Private
:
59 p
|= CodeCompletionModel::Private
;
63 if (member
->isStatic())
64 p
|= CodeCompletionModel::Static
;
67 if (member
->isFriend())
68 p
|= CodeCompletionModel::Friend
;
69 if (member
->isRegister())
71 if (member
->isExtern())
73 if (member
->isMutable())
77 if (AbstractFunctionDeclaration
* function
= dynamic_cast<AbstractFunctionDeclaration
*>(dec
)) {
78 p
|= CodeCompletionModel::Function
;
79 if (function
->isVirtual())
80 p
|= CodeCompletionModel::Virtual
;
81 if (function
->isInline())
82 p
|= CodeCompletionModel::Inline
;
83 if (function
->isExplicit())
87 if( dec
->isTypeAlias() )
88 p
|= CodeCompletionModel::TypeAlias
;
90 if (dec
->abstractType()) {
91 switch (dec
->abstractType()->whichType()) {
92 case AbstractType::TypeIntegral
:
93 p
|= CodeCompletionModel::Variable
;
95 case AbstractType::TypePointer
:
96 p
|= CodeCompletionModel::Variable
;
98 case AbstractType::TypeReference
:
99 p
|= CodeCompletionModel::Variable
;
101 case AbstractType::TypeFunction
:
102 p
|= CodeCompletionModel::Function
;
104 case AbstractType::TypeStructure
:
105 p
|= CodeCompletionModel::Class
;
107 case AbstractType::TypeArray
:
108 p
|= CodeCompletionModel::Variable
;
110 case AbstractType::TypeEnumeration
:
111 case AbstractType::TypeEnumerator
:
112 p
|= CodeCompletionModel::Enum
;
114 case AbstractType::TypeAbstract
:
115 case AbstractType::TypeDelayed
:
120 if( dec
->kind() == Declaration::Instance
)
121 p
|= CodeCompletionModel::Variable
;
124 if (dec
->context()) {
125 if( dec
->context()->type() == DUContext::Global
)
126 p
|= CodeCompletionModel::GlobalScope
;
127 else if( dec
->context()->type() == DUContext::Namespace
)
128 p
|= CodeCompletionModel::NamespaceScope
;
129 else if( dec
->context()->type() != DUContext::Class
&& dec
->context()->type() != DUContext::Enum
)
130 p
|= CodeCompletionModel::LocalScope
;
135 /**We have to construct the item from the pixmap, else the icon will be marked as "load on demand",
136 * and for some reason will be loaded every time it's used(this function returns a QIcon marked "load on demand"
137 * each time this is called). And the loading is very slow. Seems like a bug somewhere, it cannot be ment to be that slow.
139 #define RETURN_CACHED_ICON(name) {static QIcon icon(KIcon(name).pixmap(QSize(16, 16))); return icon;}
141 QIcon
DUChainUtils::iconForProperties(KTextEditor::CodeCompletionModel::CompletionProperties p
)
144 if( (p
& CodeCompletionModel::Union
) && (p
& CodeCompletionModel::Protected
) )
145 RETURN_CACHED_ICON("protected_union")
147 else if( p
& CodeCompletionModel::Enum
)
148 if( p
& CodeCompletionModel::Protected
)
149 RETURN_CACHED_ICON("protected_enum")
150 else if( p
& CodeCompletionModel::Private
)
151 RETURN_CACHED_ICON("private_enum")
153 RETURN_CACHED_ICON("enum")
155 else if( p
& CodeCompletionModel::Struct
)
156 if( p
& CodeCompletionModel::Private
)
157 RETURN_CACHED_ICON("private_struct")
159 RETURN_CACHED_ICON("struct")
161 else if( p
& CodeCompletionModel::Slot
)
162 if( p
& CodeCompletionModel::Protected
)
163 RETURN_CACHED_ICON("CVprotected_slot")
164 else if( p
& CodeCompletionModel::Private
)
165 RETURN_CACHED_ICON("CVprivate_slot")
167 RETURN_CACHED_ICON("CVpublic_slot")
169 else if( p
& CodeCompletionModel::Signal
)
170 if( p
& CodeCompletionModel::Protected
)
171 RETURN_CACHED_ICON("CVprotected_signal")
173 RETURN_CACHED_ICON("signal")
175 else if( p
& CodeCompletionModel::Class
)
176 if( (p
& CodeCompletionModel::Class
) && (p
& CodeCompletionModel::Protected
) )
177 RETURN_CACHED_ICON("protected_class")
178 else if( (p
& CodeCompletionModel::Class
) && (p
& CodeCompletionModel::Private
) )
179 RETURN_CACHED_ICON("private_class")
181 RETURN_CACHED_ICON("class")
183 else if( p
& CodeCompletionModel::Union
)
184 if( p
& CodeCompletionModel::Private
)
185 RETURN_CACHED_ICON("private_union")
187 RETURN_CACHED_ICON("union")
189 else if( p
& CodeCompletionModel::TypeAlias
)
190 if ((p
& CodeCompletionModel::Const
) /*|| (p & CodeCompletionModel::Volatile)*/)
191 RETURN_CACHED_ICON("CVtypedef")
193 RETURN_CACHED_ICON("typedef")
195 else if( p
& CodeCompletionModel::Function
)
196 if( p
& CodeCompletionModel::Protected
)
197 RETURN_CACHED_ICON("protected_function")
198 else if( p
& CodeCompletionModel::Private
)
199 RETURN_CACHED_ICON("private_function")
201 RETURN_CACHED_ICON("function")
203 else if( (p
& CodeCompletionModel::Variable
) )
204 if( (p
& CodeCompletionModel::Protected
) )
205 RETURN_CACHED_ICON("CVprotected_var")
206 else if( p
& CodeCompletionModel::Private
)
207 RETURN_CACHED_ICON("CVprivate_var")
209 RETURN_CACHED_ICON("CVpublic_var")
211 else if( p
& CodeCompletionModel::Protected
)
212 RETURN_CACHED_ICON("protected_field")
213 else if( p
& CodeCompletionModel::Private
)
214 RETURN_CACHED_ICON("private_field")
216 RETURN_CACHED_ICON("field")
221 QIcon
DUChainUtils::iconForDeclaration(Declaration
* dec
)
223 return iconForProperties(completionProperties(dec
));
226 TopDUContext
* DUChainUtils::standardContextForUrl(const KUrl
& url
) {
227 KDevelop::TopDUContext
* chosen
= 0;
229 QList
<KDevelop::ILanguage
*> languages
= ICore::self()->languageController()->languagesForUrl(url
);
231 foreach( KDevelop::ILanguage
* language
, languages
)
233 chosen
= language
->languageSupport()->standardContext(url
);
236 return DUChain::self()->chainForDocument(IndexedString(url
.pathOrUrl()));
241 Declaration
* declarationUnderCursor(const SimpleCursor
& c
, DUContext
* ctx
)
243 foreach( Declaration
* decl
, ctx
->localDeclarations() )
244 if( decl
->range().contains(c
) )
247 //Search all collapsed sub-contexts. In C++, those can contain declarations that have ranges out of the context
248 foreach( DUContext
* subCtx
, ctx
->childContexts() ) {
249 //This is a little hacky, but we need it in case of foreach macros and similar stuff
250 if(subCtx
->range().isEmpty() || subCtx
->range().start
.line
== c
.line
|| subCtx
->range().end
.line
== c
.line
) {
251 Declaration
* decl
= declarationUnderCursor(c
, subCtx
);
259 Declaration
* DUChainUtils::itemUnderCursor(const KUrl
& url
, const SimpleCursor
& c
)
261 KDevelop::TopDUContext
* chosen
= standardContextForUrl(url
);
265 DUContext
* ctx
= chosen
->findContextAt(c
);
268 //Try finding a declaration under the cursor
269 Declaration
* decl
= declarationUnderCursor(c
, ctx
);
273 //Try finding a use under the cursor
274 for(int a
= 0; a
< ctx
->usesCount(); ++a
)
275 if( ctx
->uses()[a
].m_range
.contains(c
) )
276 return ctx
->topContext()->usedDeclarationForIndex(ctx
->uses()[a
].m_declarationIndex
);
278 ctx
= ctx
->parentContext(); //It may happen, for example in the case of function-declarations, that the use is one context higher.
284 Declaration
* DUChainUtils::declarationForDefinition(Declaration
* definition
, TopDUContext
* topContext
)
290 topContext
= definition
->topContext();
292 if(dynamic_cast<FunctionDefinition
*>(definition
)) {
293 Declaration
* ret
= static_cast<FunctionDefinition
*>(definition
)->declaration();
301 Declaration
* DUChainUtils::declarationInLine(const KDevelop::SimpleCursor
& cursor
, DUContext
* ctx
) {
302 foreach(Declaration
* decl
, ctx
->localDeclarations())
303 if(decl
->range().start
.line
== cursor
.line
)
306 foreach(DUContext
* child
, ctx
->childContexts()){
307 Declaration
* decl
= declarationInLine(cursor
, child
);
315 DUChainUtils::DUChainItemFilter::~DUChainItemFilter() {
318 void DUChainUtils::collectItems( DUContext
* context
, DUChainItemFilter
& filter
) {
320 QVector
<DUContext
*> children
= context
->childContexts();
321 QVector
<Declaration
*> localDeclarations
= context
->localDeclarations();
323 QVector
<DUContext
*>::const_iterator childIt
= children
.begin();
324 QVector
<Declaration
*>::const_iterator declIt
= localDeclarations
.begin();
326 while(childIt
!= children
.end() || declIt
!= localDeclarations
.end()) {
328 DUContext
* child
= 0;
329 if(childIt
!= children
.end())
332 Declaration
* decl
= 0;
333 if(declIt
!= localDeclarations
.end())
337 if(child
&& child
->range().start
.line
>= decl
->range().start
.line
)
342 if(decl
&& decl
->range().start
>= child
->range().start
)
347 if( filter
.accept(decl
) ) {
348 //Action is done in the filter
356 if( filter
.accept(child
) )
357 collectItems(child
, filter
);
364 KDevelop::DUContext
* DUChainUtils::getArgumentContext(KDevelop::Declaration
* decl
) {
365 DUContext
* internal
= decl
->internalContext();
368 if( internal
->type() == DUContext::Function
)
370 foreach( DUContext::Import ctx
, internal
->importedParentContexts() ) {
372 if( ctx
.context()->type() == DUContext::Function
)
373 return ctx
.context();