Add AbstractDeclarationNavigationContext, and move the html-method from
[kdevelopdvcssupport.git] / language / duchain / navigation / abstractdeclarationnavigationcontext.cpp
blob1a91ee07ee5f102897dcbfa0ae885bc7127350da
1 /*
2 Copyright 2007 David Nolden <david.nolden.kdevelop@art-master.de>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
19 #include "abstractdeclarationnavigationcontext.h"
21 #include <QtGui/QTextDocument>
23 #include <klocale.h>
25 #include "../functiondeclaration.h"
26 #include "../functiondefinition.h"
27 #include "../classfunctiondeclaration.h"
28 #include "../namespacealiasdeclaration.h"
29 #include "../forwarddeclaration.h"
30 #include "../types/enumeratortype.h"
31 #include "../types/enumerationtype.h"
32 #include "../types/functiontype.h"
33 #include "../duchainutils.h"
34 #include "../types/pointertype.h"
35 #include "../types/referencetype.h"
36 #include "../types/typeutils.h"
38 namespace KDevelop {
39 AbstractDeclarationNavigationContext::AbstractDeclarationNavigationContext( DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, AbstractNavigationContext* previousContext)
40 : AbstractNavigationContext(topContext, previousContext), m_declaration(decl)
42 //Jump from definition to declaration if possible
43 FunctionDefinition* definition = dynamic_cast<FunctionDefinition*>(m_declaration.data());
44 if(definition && definition->declaration())
45 m_declaration = DeclarationPointer(definition->declaration());
48 QString AbstractDeclarationNavigationContext::name() const
50 return declarationName(m_declaration);
53 QString AbstractDeclarationNavigationContext::html(bool shorten)
55 m_linkCount = 0;
56 m_currentText = "<html><body><p><small><small>";
58 addExternalHtml(m_prefix);
60 if( shorten && !m_declaration->comment().isEmpty() ) {
61 QString comment = m_declaration->comment();
62 if( comment.length() > 60 ) {
63 comment.truncate(60);
64 comment += "...";
66 comment.replace('\n', ' ');
67 comment.replace("<br />", " ");
68 comment.replace("<br/>", " ");
69 m_currentText += commentHighlight(Qt::escape(comment)) + " ";
71 if( m_previousContext ) {
72 m_currentText += navigationHighlight("Back to ");
73 makeLink( m_previousContext->name(), m_previousContext->name(), NavigationAction(m_previousContext) );
74 m_currentText += "<br>";
77 const AbstractFunctionDeclaration* function = dynamic_cast<const AbstractFunctionDeclaration*>(m_declaration.data());
78 if( function && !shorten) {
80 qDebug() << "yyy" << m_declaration;
81 htmlFunction();
83 } else if( !shorten ) {
85 if( m_declaration->isTypeAlias() || m_declaration->kind() == Declaration::Instance ) {
86 if( m_declaration->isTypeAlias() )
87 m_currentText += importantHighlight("typedef ");
89 if(m_declaration->type<EnumeratorType>())
90 m_currentText += i18n("enumerator") + " ";
92 eventuallyMakeTypeLinks( m_declaration->abstractType() );
94 m_currentText += " " + nameHighlight(Qt::escape(declarationName(m_declaration))) + "<br>";
95 }else{
96 if( m_declaration->kind() == Declaration::Type && m_declaration->abstractType().cast<StructureType>() ) {
97 qDebug() << "xxx" << m_declaration;
98 qDebug() << "xxx" << m_declaration->abstractType().cast<StructureType>();
99 htmlClass();
102 if(m_declaration->type<EnumerationType>()) {
103 EnumerationType::Ptr enumeration = m_declaration->type<EnumerationType>();
104 m_currentText += i18n("enumeration") + " " + Qt::escape(m_declaration->identifier().toString()) + "<br>";
107 if(m_declaration->isForwardDeclaration()) {
108 ForwardDeclaration* forwardDec = static_cast<ForwardDeclaration*>(m_declaration.data());
109 Declaration* resolved = forwardDec->resolve(m_topContext.data());
110 if(resolved) {
111 m_currentText += "(" + i18n("resolved forward-declaration") + ": ";
112 makeLink(resolved->identifier().toString(), KDevelop::DeclarationPointer(resolved), NavigationAction::NavigateDeclaration );
113 m_currentText += ") ";
114 }else{
115 m_currentText += i18n("(unresolved forward-declaration)") + " ";
120 QualifiedIdentifier identifier = m_declaration->qualifiedIdentifier();
121 if( identifier.count() > 1 ) {
122 if( m_declaration->context() && m_declaration->context()->owner() )
124 Declaration* decl = m_declaration->context()->owner();
126 FunctionDefinition* definition = dynamic_cast<FunctionDefinition*>(decl);
127 if(definition && definition->declaration())
128 decl = definition->declaration();
130 if(decl->abstractType().cast<EnumerationType>())
131 m_currentText += labelHighlight(i18n("Enum: "));
132 else
133 m_currentText += labelHighlight(i18n("Container: "));
135 makeLink( declarationName(DeclarationPointer(decl)), DeclarationPointer(decl), NavigationAction::NavigateDeclaration );
136 m_currentText += " ";
137 } else {
138 QualifiedIdentifier parent = identifier;
139 parent.pop();
140 m_currentText += labelHighlight(i18n("Scope: ")) + Qt::escape(parent.toString()) + " ";
144 QString access = stringFromAccess(m_declaration);
145 if( !access.isEmpty() )
146 m_currentText += labelHighlight(i18n("Access: ")) + propertyHighlight(Qt::escape(access)) + " ";
149 ///@todo Enumerations
151 QString detailsHtml;
152 QStringList details = declarationDetails(m_declaration);
153 if( !details.isEmpty() ) {
154 bool first = true;
155 foreach( QString str, details ) {
156 if( !first )
157 detailsHtml += ", ";
158 first = false;
159 detailsHtml += propertyHighlight(str);
163 QString kind = declarationKind(m_declaration);
164 if( !kind.isEmpty() ) {
165 if( !detailsHtml.isEmpty() )
166 m_currentText += labelHighlight(i18n("Kind: ")) + importantHighlight(Qt::escape(kind)) + " " + detailsHtml + " ";
167 else
168 m_currentText += labelHighlight(i18n("Kind: ")) + importantHighlight(Qt::escape(kind)) + " ";
169 } else if( !detailsHtml.isEmpty() ) {
170 m_currentText += labelHighlight(i18n("Modifiers: ")) + importantHighlight(Qt::escape(kind)) + " ";
173 m_currentText += "<br />";
175 if( !shorten && !m_declaration->comment().isEmpty() ) {
176 QString comment = m_declaration->comment();
177 comment.replace("<br />", "\n"); //do not escape html newlines within the comment
178 comment.replace("<br/>", "\n");
179 comment = Qt::escape(comment);
180 comment.replace("\n", "<br />"); //Replicate newlines in html
181 m_currentText += commentHighlight(comment);
182 m_currentText += "<br />";
185 if( !shorten ) {
186 if(dynamic_cast<FunctionDefinition*>(m_declaration.data()))
187 m_currentText += labelHighlight(i18n( "Def.: " ));
188 else
189 m_currentText += labelHighlight(i18n( "Decl.: " ));
191 makeLink( QString("%1 :%2").arg( KUrl(m_declaration->url().str()).fileName() ).arg( m_declaration->range().textRange().start().line()+1 ), m_declaration, NavigationAction::JumpToSource );
192 m_currentText += " ";
193 //m_currentText += "<br />";
194 if(!dynamic_cast<FunctionDefinition*>(m_declaration.data())) {
195 if( FunctionDefinition* definition = FunctionDefinition::definition(m_declaration.data()) ) {
196 m_currentText += labelHighlight(i18n( " Def.: " ));
197 makeLink( QString("%1 :%2").arg( KUrl(definition->url().str()).fileName() ).arg( definition->range().textRange().start().line()+1 ), DeclarationPointer(definition), NavigationAction::JumpToSource );
201 if( FunctionDefinition* definition = dynamic_cast<FunctionDefinition*>(m_declaration.data()) ) {
202 if(definition->declaration()) {
203 m_currentText += labelHighlight(i18n( " Decl.: " ));
204 makeLink( QString("%1 :%2").arg( KUrl(definition->declaration()->url().str()).fileName() ).arg( definition->declaration()->range().textRange().start().line()+1 ), DeclarationPointer(definition->declaration()), NavigationAction::JumpToSource );
208 //m_currentText += "<br />";
211 addExternalHtml(m_suffix);
213 m_currentText += "</small></small></p></body></html>";
215 return m_currentText;
218 void AbstractDeclarationNavigationContext::htmlFunction()
220 const AbstractFunctionDeclaration* function = dynamic_cast<const AbstractFunctionDeclaration*>(m_declaration.data());
221 Q_ASSERT(function);
223 const ClassFunctionDeclaration* classFunDecl = dynamic_cast<const ClassFunctionDeclaration*>(m_declaration.data());
224 const FunctionType::Ptr type = m_declaration->abstractType().cast<FunctionType>();
225 if( !type ) {
226 m_currentText += errorHighlight("Invalid type<br>");
227 return;
229 if( !classFunDecl || !classFunDecl->isConstructor() || !classFunDecl->isDestructor() ) {
230 eventuallyMakeTypeLinks( type->returnType() );
231 m_currentText += ' ' + nameHighlight(Qt::escape(m_declaration->identifier().toString()));
234 if( type->arguments().count() == 0 )
236 m_currentText += "()";
237 } else {
238 m_currentText += "( ";
239 bool first = true;
241 KDevelop::DUContext* argumentContext = DUChainUtils::getArgumentContext(m_declaration.data());
243 if(argumentContext) {
244 int firstDefaultParam = argumentContext->localDeclarations().count() - function->defaultParametersSize();
245 int currentArgNum = 0;
247 foreach(Declaration* argument, argumentContext->localDeclarations()) {
248 if( !first )
249 m_currentText += ", ";
250 first = false;
252 AbstractType::Ptr argType = argument->abstractType();
254 eventuallyMakeTypeLinks( argType );
255 m_currentText += " " + nameHighlight(Qt::escape(argument->identifier().toString()));
257 if( currentArgNum >= firstDefaultParam )
258 m_currentText += " = " + Qt::escape(function->defaultParameters()[ currentArgNum - firstDefaultParam ].str());
260 ++currentArgNum;
264 m_currentText += " )";
266 m_currentText += "<br>";
269 void AbstractDeclarationNavigationContext::htmlClass()
271 StructureType::Ptr klass = m_declaration->abstractType().cast<StructureType>();
272 Q_ASSERT(klass);
274 m_currentText += "class ";
275 eventuallyMakeTypeLinks( klass.cast<AbstractType>() );
278 void AbstractDeclarationNavigationContext::htmlIdentifiedType(AbstractType::Ptr type, const IdentifiedType* idType)
280 Q_ASSERT(type);
281 Q_ASSERT(idType);
283 if( idType->declaration(m_topContext.data()) ) {
285 //Remove the last template-identifiers, because we create those directly
286 QualifiedIdentifier id = idType->qualifiedIdentifier();
287 Identifier lastId = id.last();
288 id.pop();
289 lastId.clearTemplateIdentifiers();
290 id.push(lastId);
292 //We leave out the * and & reference and pointer signs, those are added to the end
293 makeLink(id.toString() , DeclarationPointer(idType->declaration(m_topContext.data())), NavigationAction::NavigateDeclaration );
294 } else {
295 m_currentText += Qt::escape(type->toString());
299 void AbstractDeclarationNavigationContext::eventuallyMakeTypeLinks( AbstractType::Ptr type )
301 if( !type ) {
302 m_currentText += Qt::escape("<no type>");
303 return;
305 AbstractType::Ptr target = TypeUtils::targetType( type, m_topContext.data() );
306 const IdentifiedType* idType = dynamic_cast<const IdentifiedType*>( target.unsafeData() );
308 ///@todo handle const etc. correctly
309 PointerType::Ptr pointer = type.cast<PointerType>();
310 ReferenceType::Ptr ref = type.cast<ReferenceType>();
312 if(pointer && pointer->modifiers() & AbstractType::ConstModifier)
313 m_currentText += "const ";
314 if(ref && ref->modifiers() & AbstractType::ConstModifier)
315 m_currentText += "const ";
317 if( idType ) {
319 htmlIdentifiedType(type, idType);
321 //Add reference and pointer
322 ///@todo correct const handling
323 while(pointer || ref) {
324 if(pointer) {
325 m_currentText += Qt::escape("*");
326 ref = pointer->baseType().cast<ReferenceType>();
327 pointer = pointer->baseType().cast<PointerType>();
329 if(ref) {
330 m_currentText += Qt::escape("&");
331 pointer = ref->baseType().cast<PointerType>();
332 ref = ref->baseType().cast<ReferenceType>();
336 } else {
337 m_currentText += Qt::escape(type->toString());
341 DeclarationPointer AbstractDeclarationNavigationContext::declaration() const
343 return m_declaration;
346 QString AbstractDeclarationNavigationContext::stringFromAccess(Declaration::AccessPolicy access)
348 switch(access) {
349 case Declaration::Private:
350 return "private";
351 case Declaration::Protected:
352 return "protected";
353 case Declaration::Public:
354 return "public";
356 return "";
359 QString AbstractDeclarationNavigationContext::stringFromAccess(DeclarationPointer decl)
361 const ClassMemberDeclaration* memberDecl = dynamic_cast<const ClassMemberDeclaration*>(decl.data());
362 if( memberDecl ) {
363 return stringFromAccess(memberDecl->accessPolicy());
365 return QString();
368 QString AbstractDeclarationNavigationContext::declarationName( DeclarationPointer decl )
370 if( NamespaceAliasDeclaration* alias = dynamic_cast<NamespaceAliasDeclaration*>(decl.data()) ) {
371 if( alias->identifier().isEmpty() )
372 return "using namespace " + alias->importIdentifier().toString();
373 else
374 return "namespace " + alias->identifier().toString() + " = " + alias->importIdentifier().toString();
377 if( !decl )
378 return i18nc("An unknown declaration that is unknown", "Unknown");
379 else
380 return decl->identifier().toString();
383 QStringList AbstractDeclarationNavigationContext::declarationDetails(DeclarationPointer decl)
385 QStringList details;
386 const AbstractFunctionDeclaration* function = dynamic_cast<const AbstractFunctionDeclaration*>(decl.data());
387 const ClassMemberDeclaration* memberDecl = dynamic_cast<const ClassMemberDeclaration*>(decl.data());
388 if( memberDecl ) {
389 if( memberDecl->isMutable() )
390 details << "mutable";
391 if( memberDecl->isRegister() )
392 details << "register";
393 if( memberDecl->isStatic() )
394 details << "static";
395 if( memberDecl->isAuto() )
396 details << "auto";
397 if( memberDecl->isExtern() )
398 details << "extern";
399 if( memberDecl->isFriend() )
400 details << "friend";
403 if( decl->isDefinition() )
404 details << "definition";
406 if( memberDecl && memberDecl->isForwardDeclaration() )
407 details << "forward";
409 AbstractType::Ptr t(decl->abstractType());
410 if( t ) {
411 if( t->modifiers() & AbstractType::ConstModifier )
412 details << "constant";
413 if( t->modifiers() & AbstractType::VolatileModifier )
414 details << "volatile";
416 if( function ) {
418 if( function->isInline() )
419 details << "inline";
421 if( function->isExplicit() )
422 details << "explicit";
424 if( function->isVirtual() )
425 details << "virtual";
427 const ClassFunctionDeclaration* classFunDecl = dynamic_cast<const ClassFunctionDeclaration*>(decl.data());
429 if( classFunDecl ) {
430 if( classFunDecl->functionType() == ClassFunctionDeclaration::Signal )
431 details << "signal";
432 if( classFunDecl->functionType() == ClassFunctionDeclaration::Slot )
433 details << "slot";
434 if( classFunDecl->isConstructor() )
435 details << "constructor";
436 if( classFunDecl->isDestructor() )
437 details << "destructor";
438 if( classFunDecl->isConversionFunction() )
439 details << "conversion-function";
442 return details;