File indexing completed on 2024-05-12 04:37:45

0001 /*
0002     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "normaldeclarationcompletionitem.h"
0008 #include "codecompletionmodel.h"
0009 #include "../duchain/duchainlock.h"
0010 #include "../duchain/duchain.h"
0011 #include "../duchain/classfunctiondeclaration.h"
0012 #include "../duchain/types/functiontype.h"
0013 #include "../duchain/types/enumeratortype.h"
0014 #include "../duchain/duchainutils.h"
0015 #include "../duchain/navigation/abstractdeclarationnavigationcontext.h"
0016 #include <debug.h>
0017 
0018 #include <KTextEditor/Document>
0019 #include <KTextEditor/View>
0020 
0021 namespace KDevelop {
0022 const int NormalDeclarationCompletionItem::normalBestMatchesCount = 5;
0023 //If this is true, the return-values of argument-hints will be just written as "..." if they are too long
0024 const bool NormalDeclarationCompletionItem::shortenArgumentHintReturnValues = true;
0025 const int NormalDeclarationCompletionItem::maximumArgumentHintReturnValueLength = 30;
0026 const int NormalDeclarationCompletionItem::desiredTypeLength = 20;
0027 
0028 NormalDeclarationCompletionItem::NormalDeclarationCompletionItem(const KDevelop::DeclarationPointer& decl,
0029                                                                  const QExplicitlySharedDataPointer<CodeCompletionContext>& context,
0030                                                                  int inheritanceDepth)
0031     : m_completionContext(context)
0032     , m_declaration(decl)
0033     , m_inheritanceDepth(inheritanceDepth)
0034 {
0035 }
0036 
0037 KDevelop::DeclarationPointer NormalDeclarationCompletionItem::declaration() const
0038 {
0039     return m_declaration;
0040 }
0041 
0042 QExplicitlySharedDataPointer<KDevelop::CodeCompletionContext> NormalDeclarationCompletionItem::completionContext() const
0043 {
0044     return m_completionContext;
0045 }
0046 
0047 int NormalDeclarationCompletionItem::inheritanceDepth() const
0048 {
0049     return m_inheritanceDepth;
0050 }
0051 
0052 int NormalDeclarationCompletionItem::argumentHintDepth() const
0053 {
0054     if (m_completionContext)
0055         return m_completionContext->depth();
0056     else
0057         return 0;
0058 }
0059 
0060 QString NormalDeclarationCompletionItem::declarationName() const
0061 {
0062     if (!m_declaration) {
0063         return QStringLiteral("<unknown>");
0064     }
0065     QString ret = m_declaration->identifier().toString();
0066     if (ret.isEmpty())
0067         return QStringLiteral("<unknown>");
0068     else
0069         return ret;
0070 }
0071 
0072 void NormalDeclarationCompletionItem::execute(KTextEditor::View* view, const KTextEditor::Range& word)
0073 {
0074     if (m_completionContext && m_completionContext->depth() != 0)
0075         return; //Do not replace any text when it is an argument-hint
0076 
0077     KTextEditor::Document* document = view->document();
0078     QString newText;
0079 
0080     {
0081         KDevelop::DUChainReadLocker lock(KDevelop::DUChain::lock());
0082         if (m_declaration) {
0083             newText = declarationName();
0084         } else {
0085             qCDebug(LANGUAGE) << "Declaration disappeared";
0086             return;
0087         }
0088     }
0089 
0090     document->replaceText(word, newText);
0091     KTextEditor::Range newRange = word;
0092     newRange.setEnd(KTextEditor::Cursor(newRange.end().line(), newRange.start().column() + newText.length()));
0093 
0094     executed(view, newRange);
0095 }
0096 
0097 QWidget* NormalDeclarationCompletionItem::createExpandingWidget(const KDevelop::CodeCompletionModel* model) const
0098 {
0099     Q_UNUSED(model);
0100     return nullptr;
0101 }
0102 
0103 bool NormalDeclarationCompletionItem::createsExpandingWidget() const
0104 {
0105     return false;
0106 }
0107 
0108 QString NormalDeclarationCompletionItem::shortenedTypeString(const KDevelop::DeclarationPointer& decl,
0109                                                              int desiredTypeLength) const
0110 {
0111     Q_UNUSED(desiredTypeLength);
0112     return decl->abstractType()->toString();
0113 }
0114 
0115 void NormalDeclarationCompletionItem::executed(KTextEditor::View* view, const KTextEditor::Range& word)
0116 {
0117     Q_UNUSED(view);
0118     Q_UNUSED(word);
0119 }
0120 
0121 QVariant NormalDeclarationCompletionItem::data(const QModelIndex& index, int role,
0122                                                const KDevelop::CodeCompletionModel* model) const
0123 {
0124     DUChainReadLocker lock(DUChain::lock(), 500);
0125     if (!lock.locked()) {
0126         qCDebug(LANGUAGE) << "Failed to lock the du-chain in time";
0127         return QVariant();
0128     }
0129 
0130     if (!m_declaration)
0131         return QVariant();
0132 
0133     switch (role) {
0134     case Qt::DisplayRole:
0135         if (index.column() == CodeCompletionModel::Name) {
0136             return declarationName();
0137         } else if (index.column() == CodeCompletionModel::Postfix) {
0138             if (FunctionType::Ptr functionType = m_declaration->type<FunctionType>()) {
0139                 // Retrieve const/volatile string
0140                 return functionType->AbstractType::toString();
0141             }
0142         } else if (index.column() == CodeCompletionModel::Prefix) {
0143             if (m_declaration->kind() == Declaration::Namespace)
0144                 return QStringLiteral("namespace");
0145             if (m_declaration->abstractType()) {
0146                 if (EnumeratorType::Ptr enumerator = m_declaration->type<EnumeratorType>()) {
0147                     if (m_declaration->context()->owner() && m_declaration->context()->owner()->abstractType()) {
0148                         if (!m_declaration->context()->owner()->identifier().isEmpty())
0149                             return shortenedTypeString(DeclarationPointer(
0150                                                            m_declaration->context()->owner()), desiredTypeLength);
0151                         else
0152                             return QStringLiteral("enum");
0153                     }
0154                 }
0155                 if (FunctionType::Ptr functionType = m_declaration->type<FunctionType>()) {
0156                     auto* funDecl = dynamic_cast<ClassFunctionDeclaration*>(m_declaration.data());
0157 
0158                     if (functionType->returnType()) {
0159                         QString ret = shortenedTypeString(m_declaration, desiredTypeLength);
0160                         if (shortenArgumentHintReturnValues && argumentHintDepth() &&
0161                             ret.length() > maximumArgumentHintReturnValueLength)
0162                             return QStringLiteral("...");
0163                         else
0164                             return ret;
0165                     } else if (argumentHintDepth()) {
0166                         return QString();//Don't show useless prefixes in the argument-hints
0167                     } else if (funDecl && funDecl->isConstructor())
0168                         return QStringLiteral("<constructor>");
0169                     else if (funDecl && funDecl->isDestructor())
0170                         return QStringLiteral("<destructor>");
0171                     else
0172                         return QStringLiteral("<incomplete type>");
0173                 } else {
0174                     return shortenedTypeString(m_declaration, desiredTypeLength);
0175                 }
0176             } else {
0177                 return QStringLiteral("<incomplete type>");
0178             }
0179         } else if (index.column() == CodeCompletionModel::Arguments) {
0180             if (m_declaration->isFunctionDeclaration()) {
0181                 auto functionType = declaration()->type<FunctionType>();
0182                 return functionType ? functionType->partToString(FunctionType::SignatureArguments) : QVariant();
0183             }
0184         }
0185         break;
0186     case CodeCompletionModel::BestMatchesCount:
0187         return QVariant(normalBestMatchesCount);
0188     case CodeCompletionModel::IsExpandable:
0189         return QVariant(createsExpandingWidget());
0190     case CodeCompletionModel::ExpandingWidget: {
0191         if (!createsExpandingWidget())
0192             return {};
0193 
0194         QWidget* nav = createExpandingWidget(model);
0195         Q_ASSERT(nav);
0196 
0197         QVariant v;
0198         v.setValue<QWidget*>(nav);
0199         return v;
0200     }
0201     case CodeCompletionModel::ScopeIndex:
0202         return static_cast<int>(reinterpret_cast<quintptr>(m_declaration->context()));
0203 
0204     case CodeCompletionModel::CompletionRole:
0205         return ( int )completionProperties();
0206     case CodeCompletionModel::ItemSelected: {
0207         NavigationContextPointer ctx(new AbstractDeclarationNavigationContext(DeclarationPointer(
0208                                                                                   m_declaration),
0209                                                                               TopDUContextPointer()));
0210         return ctx->html(true);
0211     }
0212     case Qt::DecorationRole:
0213     {
0214         if (index.column() == CodeCompletionModel::Icon) {
0215             CodeCompletionModel::CompletionProperties p = completionProperties();
0216             lock.unlock();
0217             return DUChainUtils::iconForProperties(p);
0218         }
0219         break;
0220     }
0221     }
0222     return QVariant();
0223 }
0224 }