summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthijs Tijink <matthijstijink@gmail.com>2017-07-26 17:51:11 (GMT)
committerAlexander Zhigalin <alexander@zhigalin.tk>2017-07-26 18:06:19 (GMT)
commitac25815f77bb9e0006cccedbdd4ae53c5d479cc5 (patch)
treef915c58972d5baef87e315aba55e8702ebd9376a
parent9730beeb1eaa1360a94d32fa96cb071199660c0d (diff)
Process member properties/calls for unsure types in PHP
Summary: In PHP, you can only access properties and call member functions on objects. So this diff looks at an `UnsureType` and, if it contains //exactly// one `StructureType`, decides to interpret the variable as that object for this access/call. Reviewers: #kdevelop Subscribers: kdevelop-devel, #kdevelop Tags: #kdevelop Differential Revision: https://phabricator.kde.org/D6923
-rw-r--r--duchain/expressionvisitor.cpp29
-rw-r--r--duchain/tests/uses.cpp28
-rw-r--r--duchain/tests/uses.h1
3 files changed, 56 insertions, 2 deletions
diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp
index 58d51f3..68a800e 100644
--- a/duchain/expressionvisitor.cpp
+++ b/duchain/expressionvisitor.cpp
@@ -31,6 +31,7 @@
#include <language/duchain/types/functiontype.h>
#include <language/duchain/types/integraltype.h>
#include <language/duchain/types/structuretype.h>
+#include <language/duchain/types/unsuretype.h>
#include "duchaindebug.h"
@@ -567,9 +568,33 @@ void ExpressionVisitor::visitVariableProperty(VariablePropertyAst *node)
if (node->objectProperty && node->objectProperty->objectDimList) {
//handle $foo->bar() and $foo->baz, $foo is m_result.type()
- if (m_result.type() && StructureType::Ptr::dynamicCast(m_result.type())) {
+ AbstractType::Ptr type = m_result.type();
+
+ //If the variable type is unsure, try to see if it contains a StructureType. If so, use that
+ // (since the other types do not allow accessing properties)
+ if (type && type.cast<UnsureType>()) {
+ UnsureType::Ptr unsureType = type.cast<UnsureType>();
+ int numStructureType = 0;
+ StructureType::Ptr structureType;
+
+ for (unsigned int i = 0; i<unsureType->typesSize(); ++i) {
+ StructureType::Ptr subType = unsureType->types()[i].type<StructureType>();
+ if (subType) {
+ structureType = subType;
+ ++numStructureType;
+ }
+ }
+
+ //Only use the found structureType if there's exactly *one* such type
+ if (numStructureType == 1) {
+ Q_ASSERT(structureType);
+ type = AbstractType::Ptr(structureType);
+ }
+ }
+
+ if (type && StructureType::Ptr::dynamicCast(type)) {
DUChainReadLocker lock(DUChain::lock());
- Declaration* declaration = StructureType::Ptr::staticCast(m_result.type())->declaration(m_currentContext->topContext());
+ Declaration* declaration = StructureType::Ptr::staticCast(type)->declaration(m_currentContext->topContext());
if (declaration) {
ifDebug(qCDebug(DUCHAIN) << "parent:" << declaration->toString();)
DUContext* context = declaration->internalContext();
diff --git a/duchain/tests/uses.cpp b/duchain/tests/uses.cpp
index c3e1538..b51b9ac 100644
--- a/duchain/tests/uses.cpp
+++ b/duchain/tests/uses.cpp
@@ -99,6 +99,34 @@ void TestUses::memberFunctionCall()
QCOMPARE(fun->uses().keys().first(), IndexedString(QUrl("file:///internal/usestest/memberFunctionCall.php")));
}
+void TestUses::unsureMemberFunctionCall() {
+ //First try with a single unsure structure type
+
+ {
+ // 0 1 2 3 4 5 6 7 8
+ // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+ QByteArray method("<? class A { function foo() {} } if (true) { $a = new A(); } else { $a = null; } $a->foo();");
+ TopDUContext* top = parse(method, DumpNone);
+ DUChainReleaser releaseTop(top);
+ DUChainWriteLocker lock(DUChain::lock());
+ Declaration* fun = top->childContexts().first()->localDeclarations().first();
+ compareUses(fun, RangeInRevision(0, 85, 0, 88));
+ }
+
+ //Now try with two unsure structure types
+
+ {
+ // 0 1 2 3 4 5 6 7 8
+ // 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+ QByteArray method("<? class A { function foo() {} } class B {} if (true) { $a = new A(); } else { $a = new B(); } $a->foo();");
+ TopDUContext* top = parse(method, DumpNone);
+ DUChainReleaser releaseTop(top);
+ DUChainWriteLocker lock(DUChain::lock());
+ Declaration* fun = top->childContexts().first()->localDeclarations().first();
+ QCOMPARE(fun->uses().keys().count(), 0);
+ }
+}
+
void TestUses::memberVariable()
{
diff --git a/duchain/tests/uses.h b/duchain/tests/uses.h
index fa4580f..6ca46aa 100644
--- a/duchain/tests/uses.h
+++ b/duchain/tests/uses.h
@@ -34,6 +34,7 @@ private slots:
void newObject();
void functionCall();
void memberFunctionCall();
+ void unsureMemberFunctionCall();
void memberVariable();
void variable();
void varInString();