Add AbstractDeclarationNavigationContext, and move the html-method from
[kdevelopdvcssupport.git] / language / duchain / duchainutils.cpp
blobbe4b0aef7ccbf5347b6bf14d040c4e20fff6879c
1 /*
2 * DUChain Utilities
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"
35 #include "duchain.h"
36 #include "use.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;
54 break;
55 case Declaration::Protected:
56 p |= CodeCompletionModel::Protected;
57 break;
58 case Declaration::Private:
59 p |= CodeCompletionModel::Private;
60 break;
63 if (member->isStatic())
64 p |= CodeCompletionModel::Static;
65 if (member->isAuto())
66 {}//TODO
67 if (member->isFriend())
68 p |= CodeCompletionModel::Friend;
69 if (member->isRegister())
70 {}//TODO
71 if (member->isExtern())
72 {}//TODO
73 if (member->isMutable())
74 {}//TODO
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())
84 {}//TODO
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;
94 break;
95 case AbstractType::TypePointer:
96 p |= CodeCompletionModel::Variable;
97 break;
98 case AbstractType::TypeReference:
99 p |= CodeCompletionModel::Variable;
100 break;
101 case AbstractType::TypeFunction:
102 p |= CodeCompletionModel::Function;
103 break;
104 case AbstractType::TypeStructure:
105 p |= CodeCompletionModel::Class;
106 break;
107 case AbstractType::TypeArray:
108 p |= CodeCompletionModel::Variable;
109 break;
110 case AbstractType::TypeEnumeration:
111 case AbstractType::TypeEnumerator:
112 p |= CodeCompletionModel::Enum;
113 break;
114 case AbstractType::TypeAbstract:
115 case AbstractType::TypeDelayed:
116 // TODO
117 break;
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;
133 return p;
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")
152 else
153 RETURN_CACHED_ICON("enum")
155 else if( p & CodeCompletionModel::Struct )
156 if( p & CodeCompletionModel::Private )
157 RETURN_CACHED_ICON("private_struct")
158 else
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")
166 else
167 RETURN_CACHED_ICON("CVpublic_slot")
169 else if( p & CodeCompletionModel::Signal )
170 if( p & CodeCompletionModel::Protected )
171 RETURN_CACHED_ICON("CVprotected_signal")
172 else
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")
180 else
181 RETURN_CACHED_ICON("class")
183 else if( p & CodeCompletionModel::Union )
184 if( p & CodeCompletionModel::Private )
185 RETURN_CACHED_ICON("private_union")
186 else
187 RETURN_CACHED_ICON("union")
189 else if( p & CodeCompletionModel::TypeAlias )
190 if ((p & CodeCompletionModel::Const) /*|| (p & CodeCompletionModel::Volatile)*/)
191 RETURN_CACHED_ICON("CVtypedef")
192 else
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")
200 else
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")
208 else
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")
215 else
216 RETURN_CACHED_ICON("field")
218 return KIcon();
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)
232 if(!chosen)
233 chosen = language->languageSupport()->standardContext(url);
235 if(!chosen)
236 return DUChain::self()->chainForDocument(IndexedString(url.pathOrUrl()));
238 return chosen;
241 Declaration* declarationUnderCursor(const SimpleCursor& c, DUContext* ctx)
243 foreach( Declaration* decl, ctx->localDeclarations() )
244 if( decl->range().contains(c) )
245 return decl;
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);
252 if(decl)
253 return decl;
256 return 0;
259 Declaration* DUChainUtils::itemUnderCursor(const KUrl& url, const SimpleCursor& c)
261 KDevelop::TopDUContext* chosen = standardContextForUrl(url);
263 if( chosen )
265 DUContext* ctx = chosen->findContextAt(c);
267 while( ctx ) {
268 //Try finding a declaration under the cursor
269 Declaration* decl = declarationUnderCursor(c, ctx);
270 if(decl)
271 return decl;
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.
281 return 0;
284 Declaration* DUChainUtils::declarationForDefinition(Declaration* definition, TopDUContext* topContext)
286 if(!definition)
287 return 0;
289 if(!topContext)
290 topContext = definition->topContext();
292 if(dynamic_cast<FunctionDefinition*>(definition)) {
293 Declaration* ret = static_cast<FunctionDefinition*>(definition)->declaration();
294 if(ret)
295 return ret;
298 return definition;
301 Declaration* DUChainUtils::declarationInLine(const KDevelop::SimpleCursor& cursor, DUContext* ctx) {
302 foreach(Declaration* decl, ctx->localDeclarations())
303 if(decl->range().start.line == cursor.line)
304 return decl;
306 foreach(DUContext* child, ctx->childContexts()){
307 Declaration* decl = declarationInLine(cursor, child);
308 if(decl)
309 return decl;
312 return 0;
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())
330 child = *childIt;
332 Declaration* decl = 0;
333 if(declIt != localDeclarations.end())
334 decl = *declIt;
336 if(decl) {
337 if(child && child->range().start.line >= decl->range().start.line)
338 child = 0;
341 if(child) {
342 if(decl && decl->range().start >= child->range().start)
343 decl = 0;
346 if(decl) {
347 if( filter.accept(decl) ) {
348 //Action is done in the filter
351 ++declIt;
352 continue;
355 if(child) {
356 if( filter.accept(child) )
357 collectItems(child, filter);
358 ++childIt;
359 continue;
364 KDevelop::DUContext* DUChainUtils::getArgumentContext(KDevelop::Declaration* decl) {
365 DUContext* internal = decl->internalContext();
366 if( !internal )
367 return 0;
368 if( internal->type() == DUContext::Function )
369 return internal;
370 foreach( DUContext::Import ctx, internal->importedParentContexts() ) {
371 if( ctx.context() )
372 if( ctx.context()->type() == DUContext::Function )
373 return ctx.context();
375 return 0;