File indexing completed on 2024-04-28 15:52:42

0001 /*
0002     SPDX-FileCopyrightText: 2007 David Nolden <david.nolden.kdevelop@art-master.de>
0003     SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "declarationnavigationcontext.h"
0009 
0010 #include <QTextDocument>
0011 
0012 #include <klocalizedstring.h>
0013 
0014 #include <language/duchain/functiondefinition.h>
0015 #include <language/duchain/namespacealiasdeclaration.h>
0016 #include <language/duchain/forwarddeclaration.h>
0017 #include <language/duchain/duchainutils.h>
0018 #include <language/duchain/types/structuretype.h>
0019 #include <language/duchain/types/functiontype.h>
0020 #include <language/duchain/types/integraltype.h>
0021 #include <language/duchain/types/arraytype.h>
0022 
0023 #include "../declarations/classdeclaration.h"
0024 #include <declarations/classmethoddeclaration.h>
0025 #include <declarations/traitmethodaliasdeclaration.h>
0026 #include <declarations/traitmemberaliasdeclaration.h>
0027 #include <declarations/variabledeclaration.h>
0028 #include "helper.h"
0029 
0030 namespace Php
0031 {
0032 using namespace KDevelop;
0033 
0034 DeclarationNavigationContext::DeclarationNavigationContext(DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, AbstractNavigationContext* previousContext)
0035         : AbstractDeclarationNavigationContext(decl, topContext, previousContext)
0036 {
0037 }
0038 
0039 NavigationContextPointer DeclarationNavigationContext::registerChild(DeclarationPointer declaration)
0040 {
0041     return AbstractDeclarationNavigationContext::registerChild(new DeclarationNavigationContext(declaration, topContext(), this));
0042 }
0043 
0044 void DeclarationNavigationContext::htmlClass()
0045 {
0046     Q_ASSERT(declaration()->abstractType());
0047     auto klass = declaration()->abstractType().staticCast<StructureType>();
0048     ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration*>(klass->declaration(topContext().data()));
0049     if (classDecl) {
0050         // write class modifier
0051         switch (classDecl->classModifier()) {
0052         case ClassDeclarationData::Abstract:
0053             modifyHtml() += QStringLiteral("abstract ");
0054             break;
0055         case ClassDeclarationData::Final:
0056             modifyHtml() += QStringLiteral("final ");
0057             break;
0058         default:
0059             //nothing
0060             break;
0061         }
0062         // write class type
0063         if (classDecl->classType() == ClassDeclarationData::Interface) {
0064             modifyHtml() += QStringLiteral("interface ");
0065         } else if (classDecl->classType() == ClassDeclarationData::Trait) {
0066             modifyHtml() += QStringLiteral("trait ");
0067         } else {
0068             modifyHtml() += QStringLiteral("class ");
0069         }
0070         // write class identifier
0071         eventuallyMakeTypeLinks(declaration()->abstractType());
0072         // write inheritance
0073         if (classDecl->baseClassesSize() > 0) {
0074             AbstractType::Ptr extends;
0075             QList<AbstractType::Ptr> implements;
0076             FOREACH_FUNCTION(const BaseClassInstance& base, classDecl->baseClasses) {
0077                 StructureType::Ptr stype = base.baseClass.type<StructureType>();
0078                 if (stype) {
0079                     ClassDeclaration *classDecl = dynamic_cast<ClassDeclaration*>(stype->declaration(topContext().data()));
0080                     if (classDecl) {
0081                         if (classDecl->classType() == ClassDeclarationData::Interface) {
0082                             implements.append(base.baseClass.abstractType());
0083                         } else {
0084                             extends = base.baseClass.abstractType();
0085                         }
0086                     }
0087                 }
0088             }
0089             // write parent class
0090             if (extends) {
0091                 modifyHtml() += QStringLiteral(" extends ");
0092                 eventuallyMakeTypeLinks(extends);
0093             }
0094             // write implemented interfaces
0095             if (!implements.isEmpty()) {
0096                 modifyHtml() += QStringLiteral(" implements ");
0097                 for (QList<AbstractType::Ptr>::iterator i = implements.begin(); ;) {
0098                     eventuallyMakeTypeLinks(*i);
0099                     ++i;
0100                     if (i != implements.end()) {
0101                         modifyHtml() += QStringLiteral(", ");
0102                     } else {
0103                         break;
0104                     }
0105                 }
0106             }
0107         }
0108         modifyHtml() += QStringLiteral(" ");
0109     }
0110 }
0111 
0112 void DeclarationNavigationContext::htmlAdditionalNavigation()
0113 {
0114     if (auto member = dynamic_cast<TraitMethodAliasDeclaration*>(declaration().data())) {
0115         Declaration *dec = member->aliasedDeclaration().data();
0116         if (dec && dec->context() && dec->context()->owner()) {
0117             modifyHtml() += i18n("Use of %1 from %2<br />")
0118                             .arg(createLink(prettyQualifiedIdentifier(DeclarationPointer(dec)).toString(),
0119                                             QStringLiteral("jump_to_used"),
0120                                             NavigationAction(DeclarationPointer(dec),
0121                                                              KDevelop::NavigationAction::NavigateDeclaration)))
0122                             .arg(createLink(prettyQualifiedIdentifier(DeclarationPointer(dec->context()->owner())).toString(),
0123                                             QStringLiteral("jump_to_used_container"),
0124                                             NavigationAction(DeclarationPointer(dec->context()->owner()),
0125                                                              KDevelop::NavigationAction::NavigateDeclaration)));
0126         }
0127     } else if (auto member = dynamic_cast<TraitMemberAliasDeclaration*>(declaration().data())) {
0128         Declaration *dec = member->aliasedDeclaration().data();
0129         if (dec && dec->context() && dec->context()->owner()) {
0130             modifyHtml() += i18n("Use of %1 from %2<br />")
0131                             .arg(createLink(prettyQualifiedIdentifier(DeclarationPointer(dec)).toString(),
0132                                             QStringLiteral("jump_to_used"),
0133                                             NavigationAction(DeclarationPointer(dec),
0134                                                              KDevelop::NavigationAction::NavigateDeclaration)))
0135                             .arg(createLink(prettyQualifiedIdentifier(DeclarationPointer(dec->context()->owner())).toString(),
0136                                             QStringLiteral("jump_to_used_container"),
0137                                             NavigationAction(DeclarationPointer(dec->context()->owner()),
0138                                                              KDevelop::NavigationAction::NavigateDeclaration)));
0139         } else {
0140             modifyHtml() += i18n("Broken member alias trait.");
0141         }
0142     }
0143 
0144     KDevelop::AbstractDeclarationNavigationContext::htmlAdditionalNavigation();
0145 }
0146 
0147 void DeclarationNavigationContext::htmlFunction()
0148 {
0149   const AbstractFunctionDeclaration* function = dynamic_cast<const AbstractFunctionDeclaration*>(declaration().data());
0150   Q_ASSERT(function);
0151 
0152   const ClassFunctionDeclaration* classFunDecl = dynamic_cast<const ClassFunctionDeclaration*>(declaration().data());
0153   const auto type = declaration()->abstractType().dynamicCast<FunctionType>();
0154   if( !type ) {
0155     modifyHtml() += errorHighlight(QStringLiteral("Invalid type<br />"));
0156     return;
0157   }
0158 
0159   if( !classFunDecl || (!classFunDecl->isConstructor() && !classFunDecl->isDestructor()) ) {
0160     // only print return type for global functions and non-ctor/dtor methods
0161     eventuallyMakeTypeLinks( type->returnType() );
0162   }
0163 
0164   modifyHtml() += ' ' + identifierHighlight(prettyIdentifier(declaration()).toString().toHtmlEscaped(), declaration());
0165 
0166   if( type->indexedArgumentsSize() == 0 )
0167   {
0168     modifyHtml() += QStringLiteral("()");
0169   } else {
0170     modifyHtml() += QStringLiteral("( ");
0171 
0172     bool first = true;
0173     int firstDefaultParam = type->indexedArgumentsSize() - function->defaultParametersSize();
0174     int currentArgNum = 0;
0175 
0176     QVector<Declaration*> decls;
0177     if (DUContext* argumentContext = DUChainUtils::argumentContext(declaration().data())) {
0178       decls = argumentContext->localDeclarations(topContext().data());
0179     }
0180     foreach(const AbstractType::Ptr& argType, type->arguments()) {
0181       if( !first )
0182         modifyHtml() += QStringLiteral(", ");
0183       first = false;
0184 
0185       VariableDeclaration *argDec = nullptr;
0186 
0187       if (!decls.isEmpty()) {
0188         argDec = dynamic_cast<VariableDeclaration*>(decls[currentArgNum]);
0189       }
0190 
0191       if (argDec && argDec->isVariadic()) {
0192         AbstractType::Ptr variadicType;
0193         const auto a_type = argType.dynamicCast<KDevelop::ArrayType>();
0194         if (a_type) {
0195             variadicType = a_type->elementType();
0196         } else {
0197             variadicType = AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed));
0198         }
0199         modifyHtml() += QStringLiteral("[");
0200         eventuallyMakeTypeLinks( variadicType );
0201         if (currentArgNum < decls.size()) {
0202           modifyHtml() += QStringLiteral(" ...") + identifierHighlight(decls[currentArgNum]->identifier().toString().toHtmlEscaped(), declaration());
0203         }
0204         modifyHtml() += QStringLiteral("]");
0205       } else {
0206         eventuallyMakeTypeLinks( argType );
0207         if (currentArgNum < decls.size()) {
0208           modifyHtml() += ' ' + identifierHighlight(decls[currentArgNum]->identifier().toString().toHtmlEscaped(), declaration());
0209         }
0210 
0211         if (currentArgNum >= firstDefaultParam) {
0212           IndexedString defaultStr = function->defaultParameters()[currentArgNum - firstDefaultParam];
0213           if (!defaultStr.isEmpty()) {
0214             modifyHtml() += " = " + defaultStr.str().toHtmlEscaped();
0215           }
0216         }
0217       }
0218 
0219       ++currentArgNum;
0220     }
0221 
0222     modifyHtml() += QStringLiteral(" )");
0223   }
0224   modifyHtml() += QStringLiteral("<br />");
0225 }
0226 
0227 QualifiedIdentifier DeclarationNavigationContext::prettyQualifiedIdentifier(const DeclarationPointer& decl) const
0228 {
0229     return QualifiedIdentifier(prettyName(decl.data()));
0230 }
0231 
0232 void DeclarationNavigationContext::makeLink(const QString& name, const DeclarationPointer& declaration, NavigationAction::Type actionType)
0233 {
0234     if ( actionType == NavigationAction::JumpToSource && declaration->url() == internalFunctionFile() ) {
0235         modifyHtml() += i18n("PHP internal");
0236         return;
0237     }
0238     AbstractDeclarationNavigationContext::makeLink(name, declaration, actionType);
0239 }
0240 
0241 QString DeclarationNavigationContext::declarationKind(const DeclarationPointer& decl)
0242 {
0243     if ( decl->kind() == Declaration::Instance && decl->abstractType()
0244          && decl->abstractType()->modifiers() & AbstractType::ConstModifier ) {
0245         return i18nc("kind of a php-constant, as shown in the declaration tooltip", "Constant");
0246     }
0247     return AbstractDeclarationNavigationContext::declarationKind(decl);
0248 }
0249 
0250 }