File indexing completed on 2024-04-21 15:24:06

0001 /*
0002     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
0003     SPDX-FileCopyrightText: 2008 Hamish Rodda <rodda@kde.org>
0004     SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "item.h"
0010 
0011 #include <KTextEditor/Range>
0012 #include <KTextEditor/View>
0013 #include <KTextEditor/Document>
0014 
0015 #include <language/duchain/duchain.h>
0016 #include <language/duchain/duchainlock.h>
0017 #include <language/duchain/declaration.h>
0018 #include <language/duchain/namespacealiasdeclaration.h>
0019 #include <language/duchain/duchainutils.h>
0020 #include <language/duchain/types/functiontype.h>
0021 #include <language/codecompletion/codecompletionmodel.h>
0022 #include <language/codecompletion/codecompletionhelper.h>
0023 
0024 #include "../duchain/declarations/classdeclaration.h"
0025 #include "../duchain/declarations/classmethoddeclaration.h"
0026 #include "../duchain/declarations/variabledeclaration.h"
0027 #include "../duchain/types/structuretype.h"
0028 #include "../duchain/navigation/navigationwidget.h"
0029 #include "../duchain/helper.h"
0030 
0031 #include "helpers.h"
0032 #include "context.h"
0033 #include "completiondebug.h"
0034 
0035 using namespace KDevelop;
0036 
0037 namespace Php
0038 {
0039 
0040 QString NormalDeclarationCompletionItem::declarationName() const
0041 {
0042     QString ret = prettyName(m_declaration.data());
0043     if ( ret.isEmpty() ) {
0044         return QStringLiteral("<unknown>");
0045     }
0046     bool isStatic = false;
0047     if (!m_declaration->isFunctionDeclaration()) {
0048         if (dynamic_cast<VariableDeclaration*>(m_declaration.data())) {
0049             ret = '$' + ret;
0050         } else if (ClassMemberDeclaration* memberDec = dynamic_cast<ClassMemberDeclaration*>(m_declaration.data())) {
0051             isStatic = memberDec->isStatic();
0052             if (memberDec->isStatic() && memberDec->abstractType() && !(memberDec->abstractType()->modifiers() & AbstractType::ConstModifier)) {
0053                 // PHP is strange, $obj->asdf, class::const but class::$static ...
0054                 ret = '$' + ret;
0055             }
0056         }
0057     } else if ( ClassFunctionDeclaration* funDec = dynamic_cast<ClassFunctionDeclaration*>(m_declaration.data()) ) {
0058         isStatic = funDec->isStatic();
0059     }
0060 
0061     const QExplicitlySharedDataPointer<CodeCompletionContext>& ctx = completionContext();
0062 
0063     if ( ctx->memberAccessOperation() == CodeCompletionContext::NoMemberAccess ) {
0064         // if we complete a class member or method (inside a method)
0065         // we might have to add "self::", "parent::" or "$this->"
0066         if ( ctx->duContext() && ctx->duContext()->parentContext()
0067                 && ctx->duContext()->parentContext()->type() == DUContext::Class )
0068         {
0069             if ( m_declaration->context() && m_declaration->context()->type() == DUContext::Class ) {
0070                 if ( isStatic ) {
0071                     ret = "self::" + ret;
0072                 } else {
0073                     ret = "$this->" + ret;
0074                 }
0075             }
0076         }
0077     }
0078     return ret;
0079 }
0080 
0081 void NormalDeclarationCompletionItem::executed(KTextEditor::View* view, const KTextEditor::Range& word)
0082 {
0083     if (m_declaration && dynamic_cast<AbstractFunctionDeclaration*>(m_declaration.data())) {
0084         //Do some intelligent stuff for functions with the parens:
0085         insertFunctionParenText(view, word.end(), m_declaration);
0086     }
0087 }
0088 
0089 QVariant NormalDeclarationCompletionItem::data(const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model) const
0090 {
0091 
0092     DUChainReadLocker lock(DUChain::lock(), 500);
0093     if (!lock.locked()) {
0094         qCDebug(COMPLETION) << "Failed to lock the du-chain in time";
0095         return QVariant();
0096     }
0097 
0098     if (!m_declaration) {
0099         return QVariant();
0100     }
0101 
0102     Declaration* dec = const_cast<Declaration*>(m_declaration.data());
0103 
0104     switch (role) {
0105     case CodeCompletionModel::ItemSelected:
0106         return QVariant(NavigationWidget::shortDescription(dec));
0107     case Qt::DisplayRole:
0108         switch (index.column()) {
0109         case CodeCompletionModel::Postfix:
0110             return QVariant();
0111         case CodeCompletionModel::Prefix:
0112             if (dec->kind() == Declaration::Type && !dec->isTypeAlias()) {
0113                 if (dec->isFunctionDeclaration()) {
0114                     FunctionType::Ptr funcType = dec->type<FunctionType>();
0115                     if ( funcType && funcType->returnType() ) {
0116                         return funcType->returnType()->toString();
0117                     } else {
0118                         return "<notype>";
0119                     }
0120                 } else if (dec->internalContext() && dec->internalContext()->type() == DUContext::Class) {
0121                     ClassDeclaration* classDec = dynamic_cast<ClassDeclaration*>(dec);
0122                     if (classDec) {
0123                         if (classDec->classType() == ClassDeclarationData::Interface) {
0124                             return "interface";
0125                         } else {
0126                             return "class";
0127                         }
0128                     }
0129                 }
0130                 return QVariant();
0131             }  else if (dec->kind() == Declaration::Namespace) {
0132                 return "namespace";
0133             }
0134         break;
0135 
0136         case CodeCompletionModel::Arguments:
0137             if (FunctionType::Ptr functionType = dec->type<FunctionType>()) {
0138                 QString ret;
0139                 createArgumentList(*this, ret, nullptr);
0140                 return ret;
0141             }
0142             break;
0143         }
0144         break;
0145     case CodeCompletionModel::HighlightingMethod:
0146         if (index.column() == CodeCompletionModel::Arguments) {
0147             if (completionContext()->memberAccessOperation() == CodeCompletionContext::FunctionCallAccess) {
0148                 return QVariant(CodeCompletionModel::CustomHighlighting);
0149             } else {
0150                 return QVariant();
0151             }
0152             break;
0153         }
0154 
0155         break;
0156 
0157     case CodeCompletionModel::CustomHighlight:
0158         if (index.column() == CodeCompletionModel::Arguments && completionContext()->memberAccessOperation() == CodeCompletionContext::FunctionCallAccess) {
0159             QString ret;
0160             QList<QVariant> highlight;
0161             createArgumentList(*this, ret, &highlight);
0162             return QVariant(highlight);
0163         }
0164         break;
0165     }
0166     lock.unlock();
0167 
0168     return KDevelop::NormalDeclarationCompletionItem::data(index, role, model);
0169 }
0170 
0171 QWidget* NormalDeclarationCompletionItem::createExpandingWidget(const KDevelop::CodeCompletionModel* model) const
0172 {
0173     return new NavigationWidget(m_declaration, model->currentTopContext());
0174 }
0175 
0176 bool NormalDeclarationCompletionItem::createsExpandingWidget() const
0177 {
0178     return true;
0179 }
0180 
0181 QExplicitlySharedDataPointer<Php::CodeCompletionContext> NormalDeclarationCompletionItem::completionContext() const
0182 {
0183     auto context = dynamic_cast<Php::CodeCompletionContext*>(m_completionContext.data());
0184     return QExplicitlySharedDataPointer<Php::CodeCompletionContext>(context);
0185 }
0186 
0187 
0188 }
0189