diff --git a/codecompletion/items/functionitem.cpp b/codecompletion/items/functionitem.cpp index 4af9904..6b42a9d 100644 --- a/codecompletion/items/functionitem.cpp +++ b/codecompletion/items/functionitem.cpp @@ -1,240 +1,240 @@ /************************************************************************************* * Copyright (C) 2014 by Pavel Petrushkov * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #include "functionitem.h" #include #include #include #include #include #include #include #include "types/gofunctiontype.h" #include "declarations/functiondeclaration.h" namespace go { FunctionCompletionItem::FunctionCompletionItem(DeclarationPointer declaration, int depth, int atArgument): CompletionItem(declaration, QExplicitlySharedDataPointer(), 0), m_depth(depth), m_atArgument(atArgument) { auto functionDeclaration = declaration.dynamicCast(); auto functionDefinition = declaration.dynamicCast(); if(functionDeclaration) { DUChainReadLocker lock; auto decls = declaration->context()->findDeclarations(declaration->qualifiedIdentifier()); for(auto decl : decls) { auto definition = dynamic_cast(decl); if(definition) { functionDefinition = definition; } } } GoFunctionType::Ptr type(fastCast(declaration->abstractType().constData())); if(!type) return; bool variadicArgs = false; if(type->modifiers() == go::GoFunctionType::VariadicArgument) variadicArgs = true; DUContext* argsContext = nullptr; if(functionDefinition) { DUChainReadLocker lock; - argsContext = DUChainUtils::getArgumentContext(functionDefinition.data()); + argsContext = DUChainUtils::argumentContext(functionDefinition.data()); } else if(functionDeclaration) { DUChainReadLocker lock; - argsContext = DUChainUtils::getArgumentContext(functionDeclaration.data()); + argsContext = DUChainUtils::argumentContext(functionDeclaration.data()); } m_arguments = "("; if(argsContext) { DUChainReadLocker lock; auto args = argsContext->allDeclarations(CursorInRevision::invalid(), declaration->topContext(), false); //highlight last argument if it is variadic if(variadicArgs && m_atArgument >= args.size()) m_atArgument = args.size() - 1; int count = 0; for(auto arg : args) { if(m_atArgument == count) m_currentArgStart = m_arguments.length(); m_arguments += (arg.first->toString()); if(m_atArgument == count) m_currentArgEnd = m_arguments.length(); count++; if(count < args.size()) m_arguments += ", "; } }else if(type->arguments().size() != 0) { DUChainReadLocker lock; auto args = type->arguments(); int count = 0; if(variadicArgs && m_atArgument >= args.size()) m_atArgument = args.size() - 1; for(auto arg : args) { if(m_atArgument == count) m_currentArgStart = m_arguments.length(); m_arguments += (arg->toString()); if(m_atArgument == count) m_currentArgEnd = m_arguments.length(); count++; if(count < args.size()) m_arguments += ", "; } } if(variadicArgs && m_arguments.lastIndexOf('[') != -1) { if(m_currentArgEnd >= m_arguments.lastIndexOf('[')) m_currentArgEnd++; //fix highlighting m_arguments = m_arguments.replace(m_arguments.lastIndexOf('['), 2, "..."); } m_arguments += ")"; DUContext* returnContext = 0; if(functionDefinition) { returnContext = functionDefinition->returnArgsContext(); } else if(functionDeclaration) { returnContext = functionDeclaration->returnArgsContext(); } m_prefix = ""; if(returnContext) { DUChainReadLocker lock; auto args = returnContext->allDeclarations(CursorInRevision::invalid(), declaration->topContext(), false); int count = 0; for(auto arg : args) { m_prefix += (arg.first->toString()); count++; if(count < args.size()) m_prefix += ", "; } } //if there was no return context or it didn't contain anything try type if((!returnContext || m_prefix == "") && type->returnArguments().size() != 0) { int count = 0; DUChainReadLocker lock; auto args = type->returnArguments(); for(auto arg : args) { m_prefix += arg->toString(); count++; if(count < args.size()) m_prefix += ", "; } } } void FunctionCompletionItem::executed(KTextEditor::View* view, const KTextEditor::Range& word) { KTextEditor::Document* document = view->document(); QString suffix = "()"; KTextEditor::Range checkSuffix(word.end().line(), word.end().column(), word.end().line(), document->lineLength(word.end().line())); if(document->text(checkSuffix).startsWith('(')) { suffix.clear(); } document->replaceText(word, declaration()->identifier().toString() + suffix); AbstractType::Ptr type = declaration()->abstractType(); if(fastCast(type.constData())) { GoFunctionType* ftype = fastCast(type.constData()); //put cursor inside parentheses if function takes arguments if(ftype->arguments().size() > 0) view->setCursorPosition(KTextEditor::Cursor(word.end().line(), word.end().column() + 1)); } } QVariant FunctionCompletionItem::data(const QModelIndex& index, int role, const CodeCompletionModel* model) const { switch(role) { case Qt::DisplayRole: { switch (index.column()) { case CodeCompletionModel::Prefix: return m_prefix; case CodeCompletionModel::Arguments: return m_arguments; } break; } case CodeCompletionModel::CompletionRole: return (int)completionProperties(); case CodeCompletionModel::HighlightingMethod: if (index.column() == CodeCompletionModel::Arguments) { return (int)CodeCompletionModel::CustomHighlighting; } break; case KDevelop::CodeCompletionModel::CustomHighlight: { if (index.column() == CodeCompletionModel::Arguments && m_atArgument != -1) { QTextFormat format; format.setBackground(QBrush(QColor::fromRgb(142, 186, 255))); // Same color as kdev-python format.setProperty(QTextFormat::FontWeight, 99); return QVariantList() << m_currentArgStart << m_currentArgEnd - m_currentArgStart << format; } } } return CompletionItem::data(index, role, model); } CodeCompletionModel::CompletionProperties FunctionCompletionItem::completionProperties() const { return CodeCompletionModel::Function; } int FunctionCompletionItem::argumentHintDepth() const { return m_depth; } int FunctionCompletionItem::inheritanceDepth() const { return 0; } } diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp index 869ec89..a0c2e4f 100644 --- a/duchain/navigation/declarationnavigationcontext.cpp +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -1,468 +1,468 @@ /************************************************************************************* * Copyright (C) 2014 by Pavel Petrushkov * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 2 * * of the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ //most of this code is just a copy of AbstractDeclarationNavigationContext //because default html behaviour really doesn't work for go //mostly because it skips type declaration which are not structure types(identified types) //TODO come up with a better way to do all this #include #include #include #include #include #include //... #include #include #include #include #include "language/duchain/functiondeclaration.h" #include "language/duchain/functiondefinition.h" #include "language/duchain/classfunctiondeclaration.h" #include "language/duchain/namespacealiasdeclaration.h" #include "language/duchain/forwarddeclaration.h" #include "language/duchain/types/enumeratortype.h" #include "language/duchain/types/enumerationtype.h" #include "language/duchain/types/functiontype.h" #include "language/duchain/duchainutils.h" #include "language/duchain/types/pointertype.h" #include "language/duchain/types/referencetype.h" #include "language/duchain/types/typeutils.h" #include "language/duchain/persistentsymboltable.h" #include "language/duchain/types/arraytype.h" #include #include #include "navigation/declarationnavigationcontext.h" #include "declarations/functiondeclaration.h" #include "types/gofunctiontype.h" #include "../duchaindebug.h" using namespace KDevelop; DeclarationNavigationContext::DeclarationNavigationContext(DeclarationPointer decl, KDevelop::TopDUContextPointer topContext, AbstractNavigationContext* previousContext) : AbstractDeclarationNavigationContext(decl, topContext, previousContext) { } QString DeclarationNavigationContext::html(bool shorten) { clear(); AbstractNavigationContext::html(shorten); modifyHtml() += "

" + fontSizePrefix(shorten); addExternalHtml(prefix()); if(!declaration().data()) { modifyHtml() += i18n("
lost declaration
"); return currentHtml(); } if( previousContext() ) { QString link = createLink( previousContext()->name(), previousContext()->name(), NavigationAction(previousContext()) ); modifyHtml() += navigationHighlight(i18n("Back to %1
", link)); } QExplicitlySharedDataPointer doc; if( !shorten ) { doc = ICore::self()->documentationController()->documentationForDeclaration(declaration().data()); const AbstractFunctionDeclaration* function = dynamic_cast(declaration().data()); if( function ) { htmlFunction(); } else if( declaration()->kind() == Declaration::Type || declaration()->kind() == Declaration::Instance ) { if( declaration()->kind() == Declaration::Type ) modifyHtml() += importantHighlight("type "); if(declaration()->type()) modifyHtml() += i18n("enumerator "); if( !declaration()->isTypeAlias()) modifyHtml() += ' ' + identifierHighlight(declarationName(declaration()).toHtmlEscaped(), declaration()) + " "; AbstractType::Ptr useType = declaration()->abstractType(); if(declaration()->isTypeAlias()) { //Do not show the own name as type of typedefs if(useType.cast()) useType = useType.cast()->type(); } eventuallyMakeTypeLinks( useType ); modifyHtml() += "
"; }else{ if( declaration()->kind() == Declaration::Type && declaration()->abstractType().cast()) { htmlClass(); } if ( declaration()->kind() == Declaration::Namespace ) { modifyHtml() += i18n("namespace %1 ", identifierHighlight(declaration()->qualifiedIdentifier().toString().toHtmlEscaped(), declaration())); } if(declaration()->type()) { EnumerationType::Ptr enumeration = declaration()->type(); modifyHtml() += i18n("enumeration %1 ", identifierHighlight(declaration()->identifier().toString().toHtmlEscaped(), declaration())); } if(declaration()->isForwardDeclaration()) { ForwardDeclaration* forwardDec = static_cast(declaration().data()); Declaration* resolved = forwardDec->resolve(topContext().data()); if(resolved) { modifyHtml() += i18n("( resolved forward-declaration: "); makeLink(resolved->identifier().toString(), KDevelop::DeclarationPointer(resolved), NavigationAction::NavigateDeclaration ); modifyHtml() += i18n(") "); }else{ modifyHtml() += i18n("(unresolved forward-declaration) "); QualifiedIdentifier id = forwardDec->qualifiedIdentifier(); uint count; const IndexedDeclaration* decls; PersistentSymbolTable::self().declarations(id, count, decls); for(uint a = 0; a < count; ++a) { if(decls[a].isValid() && !decls[a].data()->isForwardDeclaration()) { modifyHtml() += "
"; makeLink(i18n("possible resolution from"), KDevelop::DeclarationPointer(decls[a].data()), NavigationAction::NavigateDeclaration); modifyHtml() += ' ' + decls[a].data()->url().str(); } } } } modifyHtml() += "
"; } }else{ AbstractType::Ptr showType = declaration()->abstractType(); if(showType && showType.cast()) { showType = showType.cast()->returnType(); if(showType) modifyHtml() += labelHighlight(i18n("Returns: ")); }else if(showType) { modifyHtml() += labelHighlight(i18n("Type: ")); } if(showType) { eventuallyMakeTypeLinks(showType); modifyHtml() += " "; } } QualifiedIdentifier identifier = declaration()->qualifiedIdentifier(); if( identifier.count() > 1 ) { if( declaration()->context() && declaration()->context()->owner() ) { Declaration* decl = declaration()->context()->owner(); FunctionDefinition* definition = dynamic_cast(decl); if(definition && definition->declaration()) decl = definition->declaration(); if(decl->abstractType().cast()) modifyHtml() += labelHighlight(i18n("Enum: ")); else modifyHtml() += labelHighlight(i18n("Container: ")); makeLink( declarationName(DeclarationPointer(decl)), DeclarationPointer(decl), NavigationAction::NavigateDeclaration ); modifyHtml() += " "; } else { QualifiedIdentifier parent = identifier; parent.pop(); modifyHtml() += labelHighlight(i18n("Scope: %1 ", typeHighlight(parent.toString().toHtmlEscaped()))); } } if( shorten && !declaration()->comment().isEmpty() ) { QString comment = QString::fromUtf8(declaration()->comment()); if( comment.length() > 60 ) { comment.truncate(60); comment += "..."; } comment.replace('\n', " "); comment.replace("
", " "); comment.replace("
", " "); modifyHtml() += commentHighlight(comment.toHtmlEscaped()) + " "; } QString access = stringFromAccess(declaration()); if( !access.isEmpty() ) modifyHtml() += labelHighlight(i18n("Access: %1 ", propertyHighlight(access.toHtmlEscaped()))); ///@todo Enumerations QString detailsHtml; QStringList details = declarationDetails(declaration()); if( !details.isEmpty() ) { bool first = true; foreach( const QString &str, details ) { if( !first ) detailsHtml += ", "; first = false; detailsHtml += propertyHighlight(str); } } QString kind = declarationKind(declaration()); if( !kind.isEmpty() ) { if( !detailsHtml.isEmpty() ) modifyHtml() += labelHighlight(i18n("Kind: %1 %2 ", importantHighlight(kind.toHtmlEscaped()), detailsHtml)); else modifyHtml() += labelHighlight(i18n("Kind: %1 ", importantHighlight(kind.toHtmlEscaped()))); } else if( !detailsHtml.isEmpty() ) { modifyHtml() += labelHighlight(i18n("Modifiers: %1 ", importantHighlight(kind.toHtmlEscaped()))); } modifyHtml() += "
"; if(!shorten) htmlAdditionalNavigation(); if( !shorten ) { if(dynamic_cast(declaration().data())) modifyHtml() += labelHighlight(i18n( "Def.: " )); else modifyHtml() += labelHighlight(i18n( "Decl.: " )); makeLink( QString("%1 :%2").arg( QUrl(declaration()->url().str()).fileName() ).arg( declaration()->rangeInCurrentRevision().start().line()+1 ), declaration(), NavigationAction::JumpToSource ); modifyHtml() += " "; //modifyHtml() += "
"; if(!dynamic_cast(declaration().data())) { if( FunctionDefinition* definition = FunctionDefinition::definition(declaration().data()) ) { modifyHtml() += labelHighlight(i18n( " Def.: " )); makeLink( QString("%1 :%2").arg( QUrl(definition->url().str()).fileName() ).arg( definition->rangeInCurrentRevision().start().line()+1 ), DeclarationPointer(definition), NavigationAction::JumpToSource ); } } if( FunctionDefinition* definition = dynamic_cast(declaration().data()) ) { if(definition->declaration()) { modifyHtml() += labelHighlight(i18n( " Decl.: " )); makeLink( QString("%1 :%2").arg( QUrl(definition->declaration()->url().str()).fileName() ).arg( definition->declaration()->rangeInCurrentRevision().start().line()+1 ), DeclarationPointer(definition->declaration()), NavigationAction::JumpToSource ); } } modifyHtml() += " "; //The action name _must_ stay "show_uses", since that is also used from outside makeLink(i18n("Show uses"), "show_uses", NavigationAction(declaration(), NavigationAction::NavigateUses)); } if( !shorten && (!declaration()->comment().isEmpty() || doc) ) { modifyHtml() += "
"; QString comment = QString::fromUtf8(declaration()->comment()); if(comment.isEmpty() && doc) { comment = doc->description(); if(!comment.isEmpty()) { connect(doc.data(), SIGNAL(descriptionChanged()), this, SIGNAL(contentsChanged())); modifyHtml() += "
" + commentHighlight(comment); } } else if(!comment.isEmpty()) { comment.replace(QRegExp("
"), "\n"); //do not escape html newlines within the comment comment = comment.toHtmlEscaped(); comment.replace('\n', "
"); //Replicate newlines in html modifyHtml() += commentHighlight(comment); modifyHtml() += "
"; } } if(!shorten && doc) { modifyHtml() += "
" + i18n("Show documentation for "); makeLink( prettyQualifiedIdentifier(declaration()).toString(), declaration(), NavigationAction::ShowDocumentation ); } //modifyHtml() += "
"; addExternalHtml(suffix()); modifyHtml() += fontSizeSuffix(shorten) + "

"; return currentHtml(); } void DeclarationNavigationContext::htmlFunction() { //KDevelop::AbstractDeclarationNavigationContext::htmlFunction(); go::GoFunctionDeclaration* function = dynamic_cast(declaration().data()); go::GoFunctionDefinition* functionDefinition = dynamic_cast(declaration().data()); if(!function && functionDefinition) { Declaration *decl = DUChainUtils::declarationForDefinition(functionDefinition, topContext().data()); function = dynamic_cast(decl); } if(function && !functionDefinition) { DUChainReadLocker lock; auto decls = function->context()->findDeclarations(function->qualifiedIdentifier()); for(auto decl : decls) { auto definition = dynamic_cast(decl); if(definition) { functionDefinition = definition; } } } if(!function && !functionDefinition) AbstractDeclarationNavigationContext::htmlFunction(); const go::GoFunctionType::Ptr type = declaration()->abstractType().cast(); if( !type ) { modifyHtml() += errorHighlight("Invalid type
"); return; } /*if( !classFunDecl || (!classFunDecl->isConstructor() && !classFunDecl->isDestructor()) ) { // only print return type for global functions and non-ctor/dtor methods eventuallyMakeTypeLinks( type->returnType() ); }*/ modifyHtml() += ' ' + identifierHighlight(prettyIdentifier(declaration()).toString().toHtmlEscaped(), declaration()); if( type->indexedArgumentsSize() == 0 ) { modifyHtml() += "()"; } else { modifyHtml() += "( "; bool first = true; //int firstDefaultParam = type->indexedArgumentsSize() - function->defaultParametersSize(); int currentArgNum = 0; QVector decls; if(function) { - if (KDevelop::DUContext* argumentContext = DUChainUtils::getArgumentContext(function)) + if (KDevelop::DUContext* argumentContext = DUChainUtils::argumentContext(function)) { decls = argumentContext->localDeclarations(topContext().data()); } } if(decls.isEmpty() && functionDefinition) { - if (KDevelop::DUContext* argumentContext = DUChainUtils::getArgumentContext(functionDefinition)) + if (KDevelop::DUContext* argumentContext = DUChainUtils::argumentContext(functionDefinition)) { decls = argumentContext->localDeclarations(topContext().data()); } } foreach(const AbstractType::Ptr& argType, type->arguments()) { if( !first ) modifyHtml() += ", "; first = false; if (currentArgNum < decls.size()) { modifyHtml() += identifierHighlight(decls[currentArgNum]->identifier().toString().toHtmlEscaped(), declaration()) + " "; } if(type->modifiers() == go::GoFunctionType::VariadicArgument && currentArgNum == decls.size()-1) { modifyHtml() += "..."; if(fastCast(argType.constData())) {//show only element type in variadic parameter eventuallyMakeTypeLinks(fastCast(argType.constData())->elementType()); }else {//this shouldn't happen qCDebug(DUCHAIN) << "Variadic type was not resolved to slice type"; eventuallyMakeTypeLinks( argType ); } }else { eventuallyMakeTypeLinks( argType ); } /*if( currentArgNum >= firstDefaultParam ) modifyHtml() += " = " + Qt::escape(function->defaultParameters()[ currentArgNum - firstDefaultParam ].str());*/ ++currentArgNum; } modifyHtml() += " )"; } //return types qCDebug(DUCHAIN) << type->returnArguments().size(); if(type->returnArguments().size() != 0) { modifyHtml() += " "; int currentArgNum = 0; bool first=true; QVector decls; - /*if (KDevelop::DUContext* argumentContext = DUChainUtils::getArgumentContext(declaration().data())) { + /*if (KDevelop::DUContext* argumentContext = DUChainUtils::argumentContext(declaration().data())) { decls = argumentContext->localDeclarations(topContext().data()); }*/ if(function) { if(DUContext* retContext = function->returnArgsContext()) decls = retContext->localDeclarations(topContext().data()); } if(decls.isEmpty() && functionDefinition) { if(DUContext* retContext = functionDefinition->returnArgsContext()) decls = retContext->localDeclarations(topContext().data()); } if(type->returnArguments().size() == 1) { if(decls.size() != 0) //show declaration if one exists modifyHtml() += identifierHighlight(decls[0]->identifier().toString().toHtmlEscaped(), declaration()) + " "; eventuallyMakeTypeLinks(type->returnArguments().front()); //modifyHtml() += ' ' + nameHighlight(Qt::escape(decls[currentArgNum]->identifier().toString())); } else { modifyHtml() += "("; foreach(const AbstractType::Ptr& argType, type->returnArguments()) { if( !first ) modifyHtml() += ", "; first = false; //TODO fix parameter names if (currentArgNum < decls.size()) { modifyHtml() += identifierHighlight(decls[currentArgNum]->identifier().toString().toHtmlEscaped(), declaration()) + " "; } eventuallyMakeTypeLinks( argType ); ++currentArgNum; } modifyHtml() += ")"; } } modifyHtml() += "
"; } void DeclarationNavigationContext::eventuallyMakeTypeLinks(AbstractType::Ptr type) { if( !type) { modifyHtml() += typeHighlight(QString("").toHtmlEscaped()); return; } if(declaration()->kind() == Declaration::Type) { //Go type declaration. manually creating links QualifiedIdentifier id = declaration()->qualifiedIdentifier(); makeLink(id.toString(), DeclarationPointer(declaration()), NavigationAction::NavigateDeclaration ); } else { KDevelop::AbstractDeclarationNavigationContext::eventuallyMakeTypeLinks(type); } }