Commit 0151eb7f authored by Denis Steckelmacher's avatar Denis Steckelmacher

Use assignations to deduce the type of variables

When a value is assigned to a variable, add the type of the value to the types
the variable can have.

REVIEW: 117544
parent ab928903
......@@ -41,10 +41,14 @@ QualifiedIdentifier ContextBuilder::identifierForNode(QmlJS::AST::IdentifierProp
return QualifiedIdentifier(node->id.toString());
}
AbstractType::Ptr ContextBuilder::findType(QmlJS::AST::Node* node)
ContextBuilder::ExpressionType ContextBuilder::findType(QmlJS::AST::Node* node)
{
ExpressionType ret;
if (!node) {
return AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed));
ret.type = AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed));
return ret;
}
ExpressionVisitor visitor(currentContext());
......@@ -53,7 +57,10 @@ AbstractType::Ptr ContextBuilder::findType(QmlJS::AST::Node* node)
node->accept(this);
node->accept(&visitor);
return visitor.lastType();
ret.type = visitor.lastType();
ret.declaration = visitor.lastDeclaration();
return ret;
}
void ContextBuilder::setContextOnNode(QmlJS::AST::Node* node, DUContext* context)
......
......@@ -22,6 +22,7 @@
#include <language/duchain/builders/abstractcontextbuilder.h>
#include <language/duchain/types/abstracttype.h>
#include <language/duchain/declaration.h>
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsdocument.h>
......@@ -50,6 +51,13 @@ private:
class KDEVQMLJSDUCHAIN_EXPORT ContextBuilder : public ContextBuilderBase, public QmlJS::AST::Visitor
{
public:
struct ExpressionType
{
KDevelop::AbstractType::Ptr type;
KDevelop::DeclarationPointer declaration;
};
public:
ContextBuilder();
......@@ -63,7 +71,7 @@ public:
virtual KDevelop::TopDUContext* newTopContext(const KDevelop::RangeInRevision& range,
KDevelop::ParsingEnvironmentFile* file = 0);
KDevelop::AbstractType::Ptr findType(QmlJS::AST::Node* node);
ExpressionType findType(QmlJS::AST::Node* node);
void setParseSession(ParseSession* session);
using Visitor::visit;
......
......@@ -140,7 +140,7 @@ bool DeclarationBuilder::visit(QmlJS::AST::ReturnStatement* node)
AbstractType::Ptr returnType;
if (node->expression) {
returnType = findType(node->expression);
returnType = findType(node->expression).type;
} else {
returnType = new IntegralType(IntegralType::TypeVoid);
}
......@@ -190,7 +190,7 @@ bool DeclarationBuilder::visit(QmlJS::AST::VariableDeclaration* node)
const QualifiedIdentifier name(node->name.toString());
const RangeInRevision range = m_session->locationToRange(node->identifierToken);
const AbstractType::Ptr type = findType(node->expression);
const AbstractType::Ptr type = findType(node->expression).type;
{
DUChainWriteLocker lock;
......@@ -208,6 +208,25 @@ void DeclarationBuilder::endVisit(QmlJS::AST::VariableDeclaration* node)
closeAndAssignType();
}
bool DeclarationBuilder::visit(QmlJS::AST::BinaryExpression* node)
{
if (node->op == QSOperator::Assign) {
ContextBuilder::ExpressionType leftType = findType(node->left);
AbstractType::Ptr rightType = findType(node->right).type;
if (leftType.declaration) {
// Merge the already-known type of the variable with the new one
DUChainWriteLocker lock;
leftType.declaration->setAbstractType(QmlJS::mergeTypes(leftType.type, rightType));
}
return false; // findType has already explored node
}
return QmlJS::AST::Visitor::visit(node);
}
/*
* UI
*/
......@@ -258,7 +277,7 @@ bool DeclarationBuilder::visit(QmlJS::AST::UiScriptBinding* node)
const RangeInRevision& range = m_session->locationToRange(node->qualifiedId->identifierToken);
const QualifiedIdentifier id(node->qualifiedId->name.toString());
const AbstractType::Ptr type(findType(node->statement));
const AbstractType::Ptr type(findType(node->statement).type);
{
DUChainWriteLocker lock;
......@@ -287,7 +306,7 @@ bool DeclarationBuilder::visit(QmlJS::AST::UiPublicMember* node)
const RangeInRevision& range = m_session->locationToRange(node->identifierToken);
const QualifiedIdentifier id(node->name.toString());
const AbstractType::Ptr type = findType(node->statement);
const AbstractType::Ptr type = findType(node->statement).type;
{
DUChainWriteLocker lock;
......
......@@ -55,6 +55,7 @@ protected:
// Variables
virtual bool visit(QmlJS::AST::VariableDeclaration* node);
virtual void endVisit(QmlJS::AST::VariableDeclaration* node);
virtual bool visit(QmlJS::AST::BinaryExpression* node);
// UI
virtual bool visit(QmlJS::AST::UiObjectDefinition* node);
......
......@@ -18,6 +18,7 @@
#include "expressionvisitor.h"
#include <language/duchain/topducontext.h>
#include <language/duchain/declaration.h>
#include <language/duchain/duchainlock.h>
#include <language/duchain/types/structuretype.h>
......@@ -173,8 +174,7 @@ void ExpressionVisitor::setType(const QString& declaration)
if (dec && dec->abstractType()) {
setType(dec->abstractType());
} else {
m_lastType = NULL;
m_lastDeclaration = dec;
}
}
......@@ -184,3 +184,8 @@ AbstractType::Ptr ExpressionVisitor::lastType() const
m_lastType :
AbstractType::Ptr(new IntegralType(IntegralType::TypeMixed));
}
DeclarationPointer ExpressionVisitor::lastDeclaration() const
{
return m_lastDeclaration;
}
......@@ -34,6 +34,7 @@ public:
explicit ExpressionVisitor(KDevelop::DUContext* context);
KDevelop::AbstractType::Ptr lastType() const;
KDevelop::DeclarationPointer lastDeclaration() const;
using Visitor::visit;
using Visitor::endVisit;
......@@ -60,6 +61,7 @@ private:
private:
KDevelop::DUContext* m_context;
KDevelop::AbstractType::Ptr m_lastType;
KDevelop::DeclarationPointer m_lastDeclaration;
};
......
......@@ -42,6 +42,14 @@ var nested_conditions = (simple_compare && b < 3);
*/
var simple_shift = (a << 2);
/**
* "type" : { "toString" : "unsure (string, int)" }
*/
var hello;
hello = "world";
hello = 42;
/**
* "type" : { "toString" : "function mixed (mixed)" }
*/
......
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