Commit 53f30e5b authored by Hugues Mitonneau's avatar Hugues Mitonneau Committed by Heinz Wiesinger

Add support for "array of type"

Summary:
When you use `foreach ( $a as $e )`, when `$a` is an 'iterator of x', then type of `$e` is set to 'x'.

This patch add a syntax in `@param` and `@return` to specifiy that `$a` is an 'array of x`: `@param x[]`.
This patch add support when `$a` is an 'array of x'.

{F7663472}

Reviewers: pprkut

Reviewed By: pprkut

Subscribers: pprkut, kdevelop-devel

Tags: #kdevelop

Differential Revision: https://phabricator.kde.org/D24921
parent 12d64962
......@@ -26,8 +26,8 @@
#include <language/duchain/ducontext.h>
#include <language/duchain/declaration.h>
#include <language/duchain/types/integraltype.h>
#include <language/duchain/types/arraytype.h>
#include "../declarations/classdeclaration.h"
#include "../types/indexedcontainer.h"
#include "../types/integraltypeextended.h"
#include "../types/structuretype.h"
#include <duchaindebug.h>
......@@ -57,8 +57,35 @@ TypeBuilder::~TypeBuilder()
AbstractType::Ptr TypeBuilder::parseType(QString type, AstNode* node)
{
uint iType = 0;
type = type.trimmed();
if (type.contains('|')) {
QList<AbstractType::Ptr> types;
foreach (const QString& t, type.split('|')) {
AbstractType::Ptr subType = parseType(t, node);
if (!(IntegralType::Ptr::dynamicCast(subType) && IntegralType::Ptr::staticCast(subType)->dataType() == IntegralType::TypeMixed)) {
types << parseType(t, node);
}
}
UnsureType::Ptr ret(new UnsureType());
foreach (const AbstractType::Ptr& t, types) {
ret->addType(t->indexed());
}
return AbstractType::Ptr::staticCast(ret);
}
if (type.endsWith(QLatin1String("[]"))) {
KDevelop::ArrayType* a_type = new KDevelop::ArrayType();
a_type->setElementType(parseSimpleType(type.left(type.length() - 2), node));
return AbstractType::Ptr(a_type);
} else {
return parseSimpleType(type, node);
}
}
AbstractType::Ptr TypeBuilder::parseSimpleType(QString type, AstNode* node)
{
uint iType = 0;
if (!type.compare(QLatin1String("int"), Qt::CaseInsensitive) || !type.compare(QLatin1String("integer"), Qt::CaseInsensitive)) {
iType = IntegralType::TypeInt;
} else if (!type.compare(QLatin1String("float"), Qt::CaseInsensitive) || !type.compare(QLatin1String("double"), Qt::CaseInsensitive)) {
......@@ -101,23 +128,6 @@ AbstractType::Ptr TypeBuilder::parseType(QString type, AstNode* node)
if (decl && decl->abstractType()) {
return decl->abstractType();
}
if (type.contains('|')) {
QList<AbstractType::Ptr> types;
foreach (const QString& t, type.split('|')) {
AbstractType::Ptr subType = parseType(t, node);
if (!(IntegralType::Ptr::dynamicCast(subType) && IntegralType::Ptr::staticCast(subType)->dataType() == IntegralType::TypeMixed)) {
types << parseType(t, node);
}
}
if (!type.isEmpty()) {
UnsureType::Ptr ret(new UnsureType());
foreach (const AbstractType::Ptr& t, types) {
ret->addType(t->indexed());
}
//qCDebug(DUCHAIN) << type << ret->toString();
return AbstractType::Ptr::staticCast(ret);
}
}
iType = IntegralType::TypeMixed;
}
AbstractType::Ptr ret(new IntegralType(iType));
......@@ -572,7 +582,11 @@ void TypeBuilder::visitStatement(StatementAst* node)
}
}
}
} else if ( ArrayType::Ptr a_type = ArrayType::Ptr::dynamicCast(v.result().type()) ) {
injectType(a_type->elementType());
foundType = true;
}
if (!foundType) {
injectType(AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed)));
}
......
......@@ -115,6 +115,7 @@ private:
KDevelop::AbstractType::Ptr injectParseType(QString type, AstNode* node);
KDevelop::AbstractType::Ptr parseType(QString type, AstNode* node);
KDevelop::AbstractType::Ptr parseSimpleType(QString type, AstNode* node);
KDevelop::AbstractType::Ptr parseDocComment(AstNode* node, const QString& docCommentName);
QList<KDevelop::AbstractType::Ptr> parseDocCommentParams(AstNode* node);
};
......
......@@ -30,6 +30,7 @@
#include <language/duchain/parsingenvironment.h>
#include <language/duchain/types/unsuretype.h>
#include <language/duchain/types/integraltype.h>
#include <language/duchain/types/arraytype.h>
#include <interfaces/icore.h>
#include <interfaces/iprojectcontroller.h>
#include <interfaces/iuicontroller.h>
......@@ -44,7 +45,6 @@
#include "declarations/classdeclaration.h"
#include "declarations/classmethoddeclaration.h"
#include "declarations/functiondeclaration.h"
#include "types/indexedcontainer.h"
#include "types/integraltypeextended.h"
#include "expressionparser.h"
#include "expressionvisitor.h"
......@@ -570,9 +570,8 @@ AbstractType::Ptr parameterType(const ParameterAst* node, AbstractType::Ptr phpD
}
if (node->isVariadic != -1) {
auto *container = new IndexedContainer();
container->addEntry(type);
container->setPrettyName(IndexedString("array"));
auto *container = new KDevelop::ArrayType();
container->setElementType(type);
type = AbstractType::Ptr(container);
}
......
......@@ -30,8 +30,8 @@
#include <language/duchain/types/structuretype.h>
#include <language/duchain/types/functiontype.h>
#include <language/duchain/types/integraltype.h>
#include <language/duchain/types/arraytype.h>
#include "../types/indexedcontainer.h"
#include "../declarations/classdeclaration.h"
#include <declarations/classmethoddeclaration.h>
#include <declarations/traitmethodaliasdeclaration.h>
......@@ -198,9 +198,9 @@ void DeclarationNavigationContext::htmlFunction()
if (argDec && argDec->isVariadic()) {
AbstractType::Ptr variadicType;
const auto indexed = argType.cast<IndexedContainer>();
if (indexed && indexed->typesCount() == 1) {
variadicType = indexed->typeAt(0).abstractType();
const auto a_type = argType.cast<KDevelop::ArrayType>();
if (a_type) {
variadicType = a_type->elementType();
} else {
variadicType = AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed));
}
......
......@@ -28,6 +28,7 @@
#include <language/duchain/types/functiontype.h>
#include <language/duchain/types/integraltype.h>
#include <language/duchain/types/unsuretype.h>
#include <language/duchain/types/arraytype.h>
#include <language/duchain/namespacealiasdeclaration.h>
#include <language/editor/documentrange.h>
......@@ -44,7 +45,6 @@
#include "../types/structuretype.h"
#include "../types/integraltypeextended.h"
#include "../types/indexedcontainer.h"
#include <QStandardPaths>
......@@ -1012,11 +1012,9 @@ void TestDUChain::declareVariadicFunction()
AbstractType::Ptr arg = fun->arguments().first();
QVERIFY(arg);
QVERIFY(arg.cast<IndexedContainer>());
QCOMPARE(arg.cast<IndexedContainer>()->typesCount(), 1);
QCOMPARE(arg.cast<IndexedContainer>()->prettyName().str(), QStringLiteral("array"));
QVERIFY(arg.cast<KDevelop::ArrayType>());
AbstractType::Ptr typehint = arg.cast<IndexedContainer>()->typeAt(0).abstractType();
AbstractType::Ptr typehint = arg.cast<KDevelop::ArrayType>()->elementType();
QVERIFY(typehint);
QVERIFY(IntegralType::Ptr::dynamicCast(typehint));
QVERIFY(IntegralType::Ptr::dynamicCast(typehint)->dataType() == IntegralType::TypeMixed);
......@@ -1039,11 +1037,9 @@ void TestDUChain::declareTypehintVariadicFunction()
AbstractType::Ptr arg = fun->arguments().first();
QVERIFY(arg);
QVERIFY(arg.cast<IndexedContainer>());
QCOMPARE(arg.cast<IndexedContainer>()->typesCount(), 1);
QCOMPARE(arg.cast<IndexedContainer>()->prettyName().str(), QStringLiteral("array"));
QVERIFY(arg.cast<KDevelop::ArrayType>());
AbstractType::Ptr typehint = arg.cast<IndexedContainer>()->typeAt(0).abstractType();
AbstractType::Ptr typehint = arg.cast<KDevelop::ArrayType>()->elementType();
QVERIFY(typehint);
QCOMPARE(typehint->toString(), QStringLiteral("A"));
}
......@@ -2739,6 +2735,29 @@ void TestDUChain::foreachIterator4()
QCOMPARE(aDec->uses().begin()->size(), 4);
}
void TestDUChain::foreachArray()
{
{
QByteArray code = "<?\n"
"class Foo {};\n"
"/// @param Foo[]\n"
"function bar($a) {\n"
" foreach($a as $e){ $e; }\n"
"}\n";
TopDUContext* top = parse(code, DumpNone);
DUChainReleaser releaseTop(top);
DUChainWriteLocker lock(DUChain::lock());
DUContext* barContext = top->childContexts().last();
QCOMPARE(barContext->localScopeIdentifier(), QualifiedIdentifier("bar"));
Declaration* eDec = barContext->localDeclarations().first();
QCOMPARE(eDec->qualifiedIdentifier(), QualifiedIdentifier("bar::e"));
QVERIFY(eDec->type<StructureType>());
QCOMPARE(eDec->type<StructureType>()->qualifiedIdentifier(), QualifiedIdentifier("foo"));
}
}
void TestDUChain::returnThis()
{
QByteArray code("<? class A { \n/**\n * @return $this\n */\npublic function x() {} } ");
......
......@@ -139,6 +139,7 @@ private slots:
void foreachIterator2();
void foreachIterator3();
void foreachIterator4();
void foreachArray();
void returnThis();
void unsureReturnType();
void unsureReturnType2();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment