diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(tests) set(duchain_SRCS + types/indexedcontainer.cpp types/integraltypeextended.cpp types/structuretype.cpp builders/predeclarationbuilder.cpp diff --git a/duchain/builders/declarationbuilder.cpp b/duchain/builders/declarationbuilder.cpp --- a/duchain/builders/declarationbuilder.cpp +++ b/duchain/builders/declarationbuilder.cpp @@ -789,8 +789,9 @@ // create variable declaration for argument DUChainWriteLocker lock(DUChain::lock()); RangeInRevision newRange = editorFindRange(node->variable, node->variable); - openDefinition(identifierForNode(node->variable), newRange); - currentDeclaration()->setKind(Declaration::Instance); + VariableDeclaration *dec = openDefinition(identifierForNode(node->variable), newRange); + dec->setKind(Declaration::Instance); + dec->setVariadic(node->isVariadic != -1); } DeclarationBuilderBase::visitParameter(node); diff --git a/duchain/builders/typebuilder.cpp b/duchain/builders/typebuilder.cpp --- a/duchain/builders/typebuilder.cpp +++ b/duchain/builders/typebuilder.cpp @@ -27,6 +27,7 @@ #include #include #include "../declarations/classdeclaration.h" +#include "../types/indexedcontainer.h" #include "../types/integraltypeextended.h" #include "../types/structuretype.h" #include @@ -358,7 +359,20 @@ { AbstractType::Ptr type; if (node->isVariadic != -1) { - type = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray)); + if (node->parameterType) { + //don't use openTypeFromName as it uses cursor for findDeclarations + DeclarationPointer decl = findDeclarationImport(ClassDeclarationType, + identifierForNamespace(node->parameterType, editor())); + if (decl) { + IndexedContainer *container = new IndexedContainer(); + const IndexedString *containerType = new IndexedString("array"); + container->addEntry(decl->abstractType()); + container->setPrettyName(*containerType); + type = AbstractType::Ptr(container); + } + } else { + type = AbstractType::Ptr(new IntegralType(IntegralType::TypeArray)); + } } else if (node->parameterType) { //don't use openTypeFromName as it uses cursor for findDeclarations DeclarationPointer decl = findDeclarationImport(ClassDeclarationType, diff --git a/duchain/declarations/variabledeclaration.h b/duchain/declarations/variabledeclaration.h --- a/duchain/declarations/variabledeclaration.h +++ b/duchain/declarations/variabledeclaration.h @@ -33,18 +33,20 @@ { public: VariableDeclarationData() - : KDevelop::DeclarationData(), m_isSuperglobal(false) { + : KDevelop::DeclarationData(), m_isSuperglobal(false), m_isVariadic(false) { } VariableDeclarationData(const VariableDeclarationData& rhs) : KDevelop::DeclarationData(rhs) { m_isSuperglobal = rhs.m_isSuperglobal; + m_isVariadic = rhs.m_isVariadic; } ~VariableDeclarationData() { } bool m_isSuperglobal; +bool m_isVariadic; }; /** @@ -62,6 +64,9 @@ bool isSuperglobal() const; void setSuperglobal(bool superglobal); + bool isVariadic() const; + void setVariadic(bool variadic); + uint additionalIdentity() const override; KDevelop::DeclarationId id(bool forceDirect = false) const override; diff --git a/duchain/declarations/variabledeclaration.cpp b/duchain/declarations/variabledeclaration.cpp --- a/duchain/declarations/variabledeclaration.cpp +++ b/duchain/declarations/variabledeclaration.cpp @@ -78,4 +78,16 @@ d->m_isSuperglobal = superglobal; } +bool VariableDeclaration::isVariadic() const +{ + DUCHAIN_D(VariableDeclaration); + return d->m_isVariadic; +} + +void VariableDeclaration::setVariadic(bool variadic) +{ + DUCHAIN_D_DYNAMIC(VariableDeclaration); + d->m_isVariadic = variadic; +} + } diff --git a/duchain/navigation/declarationnavigationcontext.h b/duchain/navigation/declarationnavigationcontext.h --- a/duchain/navigation/declarationnavigationcontext.h +++ b/duchain/navigation/declarationnavigationcontext.h @@ -35,6 +35,7 @@ KDevelop::QualifiedIdentifier prettyQualifiedIdentifier( KDevelop::DeclarationPointer decl ) const override; void htmlClass() override; void htmlAdditionalNavigation() override; + void htmlFunction() override; void makeLink( const QString& name, KDevelop::DeclarationPointer declaration, KDevelop::NavigationAction::Type actionType ) override; diff --git a/duchain/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp --- a/duchain/navigation/declarationnavigationcontext.cpp +++ b/duchain/navigation/declarationnavigationcontext.cpp @@ -28,11 +28,15 @@ #include #include #include +#include +#include +#include "../types/indexedcontainer.h" #include "../declarations/classdeclaration.h" #include #include #include +#include #include "helper.h" namespace Php @@ -152,6 +156,78 @@ KDevelop::AbstractDeclarationNavigationContext::htmlAdditionalNavigation(); } +void DeclarationNavigationContext::htmlFunction() +{ + const AbstractFunctionDeclaration* function = dynamic_cast(declaration().data()); + Q_ASSERT(function); + + const ClassFunctionDeclaration* classFunDecl = dynamic_cast(declaration().data()); + const FunctionType::Ptr type = declaration()->abstractType().cast(); + if( !type ) { + modifyHtml() += errorHighlight(QStringLiteral("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() += QStringLiteral("()"); + } else { + modifyHtml() += QStringLiteral("( "); + + bool first = true; + int firstDefaultParam = type->indexedArgumentsSize() - function->defaultParametersSize(); + int currentArgNum = 0; + + QVector decls; + if (DUContext* argumentContext = DUChainUtils::getArgumentContext(declaration().data())) { + decls = argumentContext->localDeclarations(topContext().data()); + } + foreach(const AbstractType::Ptr& argType, type->arguments()) { + if( !first ) + modifyHtml() += QStringLiteral(", "); + first = false; + + VariableDeclaration *argDec = dynamic_cast(decls[currentArgNum]); + + if (argDec->isVariadic()) { + AbstractType::Ptr variadicType; + const auto indexed = argType.cast(); + if (indexed && indexed->typesCount() == 1) { + variadicType = indexed->typeAt(0).abstractType(); + } else { + variadicType = AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed)); + } + modifyHtml() += QStringLiteral("["); + eventuallyMakeTypeLinks( variadicType ); + if (currentArgNum < decls.size()) { + modifyHtml() += QStringLiteral(" ...") + identifierHighlight(decls[currentArgNum]->identifier().toString().toHtmlEscaped(), declaration()); + } + modifyHtml() += QStringLiteral("]"); + } else { + eventuallyMakeTypeLinks( argType ); + if (currentArgNum < decls.size()) { + modifyHtml() += ' ' + identifierHighlight(decls[currentArgNum]->identifier().toString().toHtmlEscaped(), declaration()); + } + + if( currentArgNum >= firstDefaultParam ) + modifyHtml() += " = " + function->defaultParameters()[ currentArgNum - firstDefaultParam ].str().toHtmlEscaped(); + } + + ++currentArgNum; + } + + modifyHtml() += QStringLiteral(" )"); + } + modifyHtml() += QStringLiteral("
"); +} + QualifiedIdentifier DeclarationNavigationContext::prettyQualifiedIdentifier( DeclarationPointer decl ) const { return QualifiedIdentifier(prettyName(decl.data())); diff --git a/duchain/types/indexedcontainer.h b/duchain/types/indexedcontainer.h new file mode 100644 --- /dev/null +++ b/duchain/types/indexedcontainer.h @@ -0,0 +1,97 @@ +/** + This file is part of KDevelop + Copyright (C) 2011 Sven Brauch + + 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, see . +**/ + + +#ifndef INDEXEDCONTAINER_H +#define INDEXEDCONTAINER_H + +#include "structuretype.h" +#include + +#include "phpduchainexport.h" + +using namespace KDevelop; + +namespace Php { + +KDEVPHPDUCHAIN_EXPORT DECLARE_LIST_MEMBER_HASH(IndexedContainerData, m_values, IndexedType) + +class KDEVPHPDUCHAIN_EXPORT IndexedContainerData : public Php::StructureTypeData +{ +public: + /// Constructor + IndexedContainerData() + : Php::StructureTypeData() + { + initializeAppendedLists(m_dynamic); + } + /// Copy constructor. \param rhs data to copy + IndexedContainerData( const IndexedContainerData& rhs ) + : Php::StructureTypeData(rhs) + { + initializeAppendedLists(m_dynamic); + copyListsFrom(rhs); + } + + ~IndexedContainerData() { + freeAppendedLists(); + }; + + START_APPENDED_LISTS_BASE(IndexedContainerData, StructureTypeData) + APPENDED_LIST_FIRST(IndexedContainerData, IndexedType, m_values) + END_APPENDED_LISTS(IndexedContainerData, m_values) +}; + + +class KDEVPHPDUCHAIN_EXPORT IndexedContainer : public Php::StructureType +{ +public: + typedef TypePtr Ptr; + + IndexedContainer(); + IndexedContainer(const IndexedContainer& rhs); + IndexedContainer(IndexedContainerData& data); + void addEntry(AbstractType::Ptr typeToAdd); + AbstractType* clone() const override; + uint hash() const override; + int typesCount() const; + const IndexedType& typeAt(int index) const; + void replaceType(int index, AbstractType::Ptr newType); + QString toString() const override; + // "toString"s only the container type, not the content; used in declarationnavigationcontext to create + // separate links for the content and container type + // by keeping toString separate, it is possible to have a pretty type in mixed types etc. without additional + // efforts being necessary + QString containerToString() const; + + bool equals(const AbstractType* rhs) const override; + + enum { +// #warning check identity value (59) + Identity = 59 + }; + + typedef IndexedContainerData Data; + +protected: + TYPE_DECLARE_DATA(IndexedContainer); +}; + +} + +#endif // INDEXEDCONTAINER_H diff --git a/duchain/types/indexedcontainer.cpp b/duchain/types/indexedcontainer.cpp new file mode 100644 --- /dev/null +++ b/duchain/types/indexedcontainer.cpp @@ -0,0 +1,134 @@ +/** + This file is part of KDevelop + Copyright (C) 2011 Sven Brauch + + 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, see . +**/ + + +#include "indexedcontainer.h" + +#include +#include +#include + +#include + +using namespace KDevelop; + +namespace Php { + +DEFINE_LIST_MEMBER_HASH(IndexedContainerData, m_values, IndexedType) +REGISTER_TYPE(IndexedContainer); + +IndexedContainer::IndexedContainer() : Php::StructureType(createData()) +{ + +} + +IndexedContainer::IndexedContainer(const IndexedContainer& rhs) + : StructureType(copyData(*rhs.d_func())) +{ + +} + +IndexedContainer::IndexedContainer(IndexedContainerData& data) + : StructureType(data) +{ + +} + +void IndexedContainer::addEntry(AbstractType::Ptr typeToAdd) +{ + Q_ASSERT(typeToAdd && "trying to add a null type to indexedContainer"); + d_func_dynamic()->m_valuesList().append(typeToAdd->indexed()); +} + +const IndexedType& IndexedContainer::typeAt(int index) const +{ + Q_ASSERT((uint) index < d_func()->m_valuesSize()); + return d_func()->m_values()[index]; +} + +void IndexedContainer::replaceType(int index, AbstractType::Ptr newType) +{ + Q_ASSERT((uint) index < d_func()->m_valuesSize()); + d_func_dynamic()->m_valuesList()[index] = newType->indexed(); +} + +KDevelop::AbstractType* IndexedContainer::clone() const +{ + IndexedContainer* n = new IndexedContainer(*this); + return n; +} + +QString IndexedContainer::toString() const +{ + QString prefix = Php::StructureType::toString(); + QStringList typesArray; + for ( int i = 0; i < typesCount(); i++ ) { + if ( i >= 5 ) { + // Don't print more than five types explicitly + typesArray << "..."; + break; + } + typesArray << typeAt(i).abstractType()->toString(); + } + const QString contentType = QStringLiteral("(") + typesArray.join(", ") + ")"; + return i18nc("as in list of int, set of string", "%1 of %2", prefix, contentType); +} + +QString IndexedContainer::containerToString() const +{ + return Php::StructureType::toString(); +} + +int IndexedContainer::typesCount() const +{ + return d_func()->m_valuesSize(); +} + +bool IndexedContainer::equals(const AbstractType* rhs) const +{ + if ( this == rhs ) { + return true; + } + if ( ! Php::StructureType::equals(rhs) ) { + return false; + } + const IndexedContainer* c = dynamic_cast(rhs); + if ( ! c ) { + return false; + } + if ( typesCount() != c->typesCount() ) { + return false; + } + for ( int i = 0; i < typesCount(); i++ ) { + if ( c->typeAt(i) != typeAt(i) ) { + return false; + } + } + return true; +} + +uint IndexedContainer::hash() const +{ + uint h = StructureType::hash(); + for ( uint i = 0; i < d_func()->m_valuesSize(); i++ ) { + h += i*d_func()->m_values()[i]; + } + return h; +} + +}