summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeinz Wiesinger <pprkut@liwjatan.at>2017-05-20 17:17:45 (GMT)
committerHeinz Wiesinger <pprkut@liwjatan.at>2017-06-18 17:21:56 (GMT)
commit1cb4b3e37e5caec095a6e14ebbc561616d9897ad (patch)
treefa8b8e686fb0b1404d0bfbfe202d6bb367954c38
parentfb372fb187354e0c52b0c68b20f5e2b275291cf7 (diff)
Support for variadic functions in documentation popup.
Summary: This shows the documentation for functions defined as ``` function foo(...$params) {} function foo(A ...$params) {} ``` in the form of ``` void foo ([mixed ...params]) void foo ([A ...params]) ``` In the first case, $params itself is shown as ``` array params ``` and in the latter as ``` array of (A) params ``` Reviewers: zhigalin Reviewed By: zhigalin Subscribers: aacid, zhigalin, kdevelop-devel Differential Revision: https://phabricator.kde.org/D6256
-rw-r--r--duchain/CMakeLists.txt1
-rw-r--r--duchain/builders/declarationbuilder.cpp5
-rw-r--r--duchain/builders/typebuilder.cpp16
-rw-r--r--duchain/declarations/variabledeclaration.cpp12
-rw-r--r--duchain/declarations/variabledeclaration.h7
-rw-r--r--duchain/navigation/declarationnavigationcontext.cpp76
-rw-r--r--duchain/navigation/declarationnavigationcontext.h1
-rw-r--r--duchain/types/indexedcontainer.cpp134
-rw-r--r--duchain/types/indexedcontainer.h97
9 files changed, 345 insertions, 4 deletions
diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt
index 834b835..fe0a2ba 100644
--- a/duchain/CMakeLists.txt
+++ b/duchain/CMakeLists.txt
@@ -2,6 +2,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
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
index e9995ac..ea29dfb 100644
--- a/duchain/builders/declarationbuilder.cpp
+++ b/duchain/builders/declarationbuilder.cpp
@@ -789,8 +789,9 @@ void DeclarationBuilder::visitParameter(ParameterAst *node)
// create variable declaration for argument
DUChainWriteLocker lock(DUChain::lock());
RangeInRevision newRange = editorFindRange(node->variable, node->variable);
- openDefinition<VariableDeclaration>(identifierForNode(node->variable), newRange);
- currentDeclaration()->setKind(Declaration::Instance);
+ VariableDeclaration *dec = openDefinition<VariableDeclaration>(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
index 209530f..0053763 100644
--- a/duchain/builders/typebuilder.cpp
+++ b/duchain/builders/typebuilder.cpp
@@ -27,6 +27,7 @@
#include <language/duchain/declaration.h>
#include <language/duchain/types/integraltype.h>
#include "../declarations/classdeclaration.h"
+#include "../types/indexedcontainer.h"
#include "../types/integraltypeextended.h"
#include "../types/structuretype.h"
#include <duchaindebug.h>
@@ -358,7 +359,20 @@ void TypeBuilder::visitParameter(ParameterAst *node)
{
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.cpp b/duchain/declarations/variabledeclaration.cpp
index 9b2760b..1453e8c 100644
--- a/duchain/declarations/variabledeclaration.cpp
+++ b/duchain/declarations/variabledeclaration.cpp
@@ -78,4 +78,16 @@ void VariableDeclaration::setSuperglobal(bool superglobal)
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/declarations/variabledeclaration.h b/duchain/declarations/variabledeclaration.h
index a8a291a..983122e 100644
--- a/duchain/declarations/variabledeclaration.h
+++ b/duchain/declarations/variabledeclaration.h
@@ -33,18 +33,20 @@ class KDEVPHPDUCHAIN_EXPORT VariableDeclarationData : public KDevelop::Declarati
{
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 @@ public:
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/navigation/declarationnavigationcontext.cpp b/duchain/navigation/declarationnavigationcontext.cpp
index fdee187..933c697 100644
--- a/duchain/navigation/declarationnavigationcontext.cpp
+++ b/duchain/navigation/declarationnavigationcontext.cpp
@@ -28,11 +28,15 @@
#include <language/duchain/forwarddeclaration.h>
#include <language/duchain/duchainutils.h>
#include <language/duchain/types/structuretype.h>
+#include <language/duchain/types/functiontype.h>
+#include <language/duchain/types/integraltype.h>
+#include "../types/indexedcontainer.h"
#include "../declarations/classdeclaration.h"
#include <declarations/classmethoddeclaration.h>
#include <declarations/traitmethodaliasdeclaration.h>
#include <declarations/traitmemberaliasdeclaration.h>
+#include <declarations/variabledeclaration.h>
#include "helper.h"
namespace Php
@@ -152,6 +156,78 @@ void DeclarationNavigationContext::htmlAdditionalNavigation()
KDevelop::AbstractDeclarationNavigationContext::htmlAdditionalNavigation();
}
+void DeclarationNavigationContext::htmlFunction()
+{
+ const AbstractFunctionDeclaration* function = dynamic_cast<const AbstractFunctionDeclaration*>(declaration().data());
+ Q_ASSERT(function);
+
+ const ClassFunctionDeclaration* classFunDecl = dynamic_cast<const ClassFunctionDeclaration*>(declaration().data());
+ const FunctionType::Ptr type = declaration()->abstractType().cast<FunctionType>();
+ if( !type ) {
+ modifyHtml() += errorHighlight(QStringLiteral("Invalid type<br />"));
+ 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<Declaration*> 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<VariableDeclaration*>(decls[currentArgNum]);
+
+ if (argDec->isVariadic()) {
+ AbstractType::Ptr variadicType;
+ const auto indexed = argType.cast<IndexedContainer>();
+ 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("<br />");
+}
+
QualifiedIdentifier DeclarationNavigationContext::prettyQualifiedIdentifier( DeclarationPointer decl ) const
{
return QualifiedIdentifier(prettyName(decl.data()));
diff --git a/duchain/navigation/declarationnavigationcontext.h b/duchain/navigation/declarationnavigationcontext.h
index e12fa5b..1ce0907 100644
--- a/duchain/navigation/declarationnavigationcontext.h
+++ b/duchain/navigation/declarationnavigationcontext.h
@@ -35,6 +35,7 @@ protected:
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/types/indexedcontainer.cpp b/duchain/types/indexedcontainer.cpp
new file mode 100644
index 0000000..6274fb1
--- /dev/null
+++ b/duchain/types/indexedcontainer.cpp
@@ -0,0 +1,134 @@
+/**
+ This file is part of KDevelop
+ Copyright (C) 2011 Sven Brauch <svenbrauch@googlemail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+**/
+
+
+#include "indexedcontainer.h"
+
+#include <language/duchain/types/typeregister.h>
+#include <language/duchain/duchain.h>
+#include <language/duchain/duchainlock.h>
+
+#include <KLocalizedString>
+
+using namespace KDevelop;
+
+namespace Php {
+
+DEFINE_LIST_MEMBER_HASH(IndexedContainerData, m_values, IndexedType)
+REGISTER_TYPE(IndexedContainer);
+
+IndexedContainer::IndexedContainer() : Php::StructureType(createData<IndexedContainer>())
+{
+
+}
+
+IndexedContainer::IndexedContainer(const IndexedContainer& rhs)
+ : StructureType(copyData<IndexedContainer>(*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<const IndexedContainer*>(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;
+}
+
+}
diff --git a/duchain/types/indexedcontainer.h b/duchain/types/indexedcontainer.h
new file mode 100644
index 0000000..25e3db5
--- /dev/null
+++ b/duchain/types/indexedcontainer.h
@@ -0,0 +1,97 @@
+/**
+ This file is part of KDevelop
+ Copyright (C) 2011 Sven Brauch <svenbrauch@googlemail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+**/
+
+
+#ifndef INDEXEDCONTAINER_H
+#define INDEXEDCONTAINER_H
+
+#include "structuretype.h"
+#include <language/duchain/types/typesystemdata.h>
+
+#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<IndexedContainer> 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