File indexing completed on 2024-04-28 04:35:52
0001 /* This file is part of KDevelop 0002 * 0003 * Copyright (C) 2011-2015 Miquel Sabaté Solà <mikisabate@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 */ 0018 0019 0020 // Qt + KDevelop 0021 #include <QtGui/QTextDocument> 0022 #include <language/duchain/types/functiontype.h> 0023 #include <language/duchain/types/structuretype.h> 0024 #include <language/duchain/duchainutils.h> 0025 0026 // Ruby 0027 #include <duchain/helpers.h> 0028 #include <duchain/declarations/methoddeclaration.h> 0029 #include <duchain/declarations/moduledeclaration.h> 0030 #include <duchain/declarations/variabledeclaration.h> 0031 #include <duchain/navigation/declarationnavigationcontext.h> 0032 0033 0034 namespace ruby 0035 { 0036 using namespace KDevelop; 0037 0038 DeclarationNavigationContext::DeclarationNavigationContext( DeclarationPointer decl, 0039 TopDUContextPointer topContext, 0040 AbstractNavigationContext *prevContext) 0041 : AbstractDeclarationNavigationContext(decl, topContext, prevContext) 0042 { 0043 /* There's nothing to do here! */ 0044 } 0045 0046 QString DeclarationNavigationContext::html(bool shorten) 0047 { 0048 clear(); 0049 AbstractDeclarationNavigationContext::html(shorten); 0050 modifyHtml() += "<html><body><p>"; 0051 0052 if(!declaration().data()) { 0053 modifyHtml() += i18n("<br /> lost declaration <br />"); 0054 return currentHtml(); 0055 } 0056 if(auto context = previousContext()) { 0057 QString link = createLink(context->name(), context->name(), NavigationAction(context)); 0058 modifyHtml() += navigationHighlight(i18n("Back to %1<br />", link)); 0059 } 0060 0061 if (!shorten) { 0062 const MethodDeclaration *mDecl = dynamic_cast<const MethodDeclaration *>(declaration().data()); 0063 if (mDecl) { 0064 if (mDecl->qualifiedIdentifier().count() > 1 && mDecl->context() && mDecl->context()->owner()) { 0065 Declaration *d = declaration()->context()->owner(); 0066 makeLink(declarationName(DeclarationPointer(d)), DeclarationPointer(d), NavigationAction::NavigateDeclaration); 0067 modifyHtml() += (mDecl->isClassMethod()) ? "::" : "#"; 0068 } 0069 htmlFunction(); 0070 } else if (declaration()->kind() == Declaration::Instance) { 0071 eventuallyMakeTypeLinks(declaration()->abstractType()); 0072 const QString &esc = declarationName(declaration()).toHtmlEscaped(); 0073 modifyHtml() += ' ' + nameHighlight(esc) + "<br>"; 0074 } else if (declaration()->kind() == Declaration::Type && declaration()->abstractType().dynamicCast<StructureType>()) { 0075 htmlClass(); 0076 } 0077 } else if (declaration()->abstractType()) { 0078 eventuallyMakeTypeLinks(declaration()->abstractType()); 0079 modifyHtml() += " "; 0080 } 0081 0082 QString access = stringFromAccess(declaration()); 0083 if (!access.isEmpty()) { 0084 access = propertyHighlight(access.toHtmlEscaped()); 0085 modifyHtml() += labelHighlight(i18n("Access: %1 ", access)); 0086 modifyHtml() += "<br />"; 0087 } 0088 0089 if (!shorten) { 0090 htmlAdditionalNavigation(); 0091 modifyHtml() += "<br />"; 0092 modifyHtml() += labelHighlight(i18n("Def.: ")); 0093 makeLink(QString("%1 :%2").arg(QUrl(declaration()->url().str()).fileName()).arg(declaration()->rangeInCurrentRevision().start().line() + 1), declaration(), NavigationAction::JumpToSource); 0094 modifyHtml() += " "; 0095 modifyHtml() += createLink(i18n("Show uses"), "show_uses", NavigationAction(declaration(), NavigationAction::NavigateUses)); 0096 if(!shorten && !declaration()->comment().isEmpty()) { 0097 modifyHtml() += "<br />"; 0098 QString comment = QString::fromUtf8(declaration()->comment()); 0099 if(!comment.isEmpty()) { 0100 comment.replace("<br />", "\n"); 0101 comment.replace("<br/>", "\n"); 0102 comment = comment.toHtmlEscaped(); 0103 comment.replace('\n', "<br />"); 0104 modifyHtml() += commentHighlight(comment); 0105 modifyHtml() += "<br />"; 0106 } 0107 } 0108 } 0109 0110 modifyHtml() += "</p></body></html>"; 0111 return currentHtml(); 0112 } 0113 0114 void DeclarationNavigationContext::htmlFunction() 0115 { 0116 const MethodDeclaration *mDecl = dynamic_cast<const MethodDeclaration *>(declaration().data()); 0117 Q_ASSERT(mDecl); 0118 0119 const auto type = declaration()->abstractType().dynamicCast<FunctionType>(); 0120 if (!type) { 0121 modifyHtml() += errorHighlight("Invalid type<br/>"); 0122 return; 0123 } 0124 0125 const QString &name = prettyIdentifier(declaration()).toString(); 0126 modifyHtml() += nameHighlight(name.toHtmlEscaped()); 0127 if (type->arguments().size() > 0) { 0128 bool first = true; 0129 int nDef = 0; 0130 DUContext *ctx = DUChainUtils::argumentContext(declaration().data()); 0131 0132 if (ctx) { 0133 modifyHtml() += "( "; 0134 foreach (Declaration *d, ctx->localDeclarations(topContext().data())) { 0135 if (!first) 0136 modifyHtml() += ", "; 0137 first = false; 0138 0139 VariableDeclaration *vd = dynamic_cast<VariableDeclaration *>(d); 0140 if (vd->hasStar()) 0141 modifyHtml() += " *"; 0142 else if (vd->isBlock()) 0143 modifyHtml() += " &"; 0144 else 0145 modifyHtml() += " "; 0146 const QString &aux = vd->identifier().toString(); 0147 modifyHtml() += nameHighlight(aux.toHtmlEscaped()); 0148 0149 if (vd->isOpt()) { 0150 const QString &str = mDecl->defaultParameters()[nDef].str(); 0151 modifyHtml() += " " + str.toHtmlEscaped(); 0152 nDef++; 0153 } 0154 } 0155 modifyHtml() += " )"; 0156 } 0157 } 0158 } 0159 0160 void DeclarationNavigationContext::htmlClass() 0161 { 0162 Q_ASSERT(declaration()->abstractType()); 0163 auto klass = declaration()->abstractType().staticCast<StructureType>(); 0164 ModuleDeclaration *mDecl = dynamic_cast<ModuleDeclaration *>(klass->declaration(topContext().data())); 0165 0166 if (mDecl) { 0167 if (mDecl->isModule()) { 0168 modifyHtml() += "module "; 0169 eventuallyMakeTypeLinks(declaration()->abstractType()); 0170 } else { 0171 modifyHtml() += "class "; 0172 eventuallyMakeTypeLinks(declaration()->abstractType()); 0173 0174 if (mDecl->baseClass()) { 0175 AbstractType::Ptr base = mDecl->baseClass().abstractType(); 0176 modifyHtml() += " is a subclass of "; 0177 eventuallyMakeTypeLinks(base); 0178 } 0179 } 0180 modifyHtml() += " "; 0181 addModuleMixins(mDecl); 0182 } 0183 } 0184 0185 void DeclarationNavigationContext::makeLink(const QString &name, const DeclarationPointer& declaration, 0186 NavigationAction::Type actionType) 0187 { 0188 if (actionType == NavigationAction::JumpToSource 0189 && declaration->url() == builtinsFile()) { 0190 modifyHtml() += i18n("Ruby Kernel"); 0191 return; 0192 } 0193 AbstractDeclarationNavigationContext::makeLink(name, declaration, actionType); 0194 } 0195 0196 void DeclarationNavigationContext::addModuleMixins(ModuleDeclaration *decl) 0197 { 0198 uint nMixins = decl->moduleMixinsSize(); 0199 QList<AbstractType::Ptr> includes, extends; 0200 ModuleMixin aux; 0201 0202 if (nMixins > 0) { 0203 for (uint i = 0; i < nMixins; i++) { 0204 aux = decl->moduleMixins()[i]; 0205 if (aux.included) 0206 includes << aux.module.abstractType(); 0207 else 0208 extends << aux.module.abstractType(); 0209 } 0210 if (!includes.isEmpty()) { 0211 modifyHtml() += "<br>Includes: "; 0212 foreach (const AbstractType::Ptr d, includes) 0213 eventuallyMakeTypeLinks(d); 0214 } 0215 if (!extends.isEmpty()) { 0216 modifyHtml() += "<br>Extends: "; 0217 foreach (const AbstractType::Ptr d, extends) 0218 eventuallyMakeTypeLinks(d); 0219 } 0220 } 0221 } 0222 0223 void DeclarationNavigationContext::addMixers(ModuleDeclaration *decl) 0224 { 0225 uint nMixers = decl->mixersSize(); 0226 const ModuleMixin *aux; 0227 0228 if (nMixers > 0) { 0229 aux = decl->mixers(); 0230 modifyHtml() += "<br>Mixed in: "; 0231 for (uint i = 0; i < nMixers; i++) { 0232 eventuallyMakeTypeLinks(aux[i].module.abstractType()); 0233 if (i != nMixers - 1) 0234 modifyHtml() += ", "; 0235 } 0236 modifyHtml() += "<br>"; 0237 } 0238 } 0239 0240 } 0241