diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp --- a/duchain/expressionvisitor.cpp +++ b/duchain/expressionvisitor.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "duchaindebug.h" @@ -567,9 +568,33 @@ 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::Ptr unsureType = type.cast(); + int numStructureType = 0; + StructureType::Ptr structureType; + + for (unsigned int i = 0; itypesSize(); ++i) { + StructureType::Ptr subType = unsureType->types()[i].type(); + 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.h b/duchain/tests/uses.h --- a/duchain/tests/uses.h +++ b/duchain/tests/uses.h @@ -34,6 +34,7 @@ void newObject(); void functionCall(); void memberFunctionCall(); + void unsureMemberFunctionCall(); void memberVariable(); void variable(); void varInString(); diff --git a/duchain/tests/uses.cpp b/duchain/tests/uses.cpp --- a/duchain/tests/uses.cpp +++ b/duchain/tests/uses.cpp @@ -99,6 +99,34 @@ 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("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("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() {