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 }