diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 349ec8efa609fbb75e29910047bb1db6f38a3034..b1893ce732d449d72fc645aedcfc6229d64d1120 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -243,7 +243,10 @@ const Value *ConvertToString::switchResult(const Value *value) {
     return previousResult;
 }
 
-ConvertToObject::ConvertToObject(Engine *engine): _engine(engine), _result(0) {}
+ConvertToObject::ConvertToObject(Engine *engine)
+    : _engine(engine), _result(0)
+{
+}
 
 const Value *ConvertToObject::operator()(const Value *value) {
     const Value *previousValue = switchResult(0);
@@ -260,6 +263,40 @@ const Value *ConvertToObject::switchResult(const Value *value) {
     return previousResult;
 }
 
+void ConvertToObject::visit(const NullValue *value)
+{
+    _result = value;
+}
+
+void ConvertToObject::visit(const UndefinedValue *)
+{
+    _result = _engine->nullValue();
+}
+
+void ConvertToObject::visit(const NumberValue *)
+{
+    _result = _engine->call(_engine->numberCtor());
+}
+
+void ConvertToObject::visit(const BooleanValue *)
+{
+    _result = _engine->call(_engine->booleanCtor());
+}
+
+void ConvertToObject::visit(const StringValue *)
+{
+    _result = _engine->call(_engine->stringCtor());
+}
+
+void ConvertToObject::visit(const ObjectValue *object)
+{
+    _result = object;
+}
+
+void ConvertToObject::visit(const FunctionValue *object)
+{
+    _result = object;
+}
 
 QString TypeId::operator()(const Value *value)
 {
@@ -913,42 +950,3 @@ void ConvertToString::visit(const FunctionValue *object)
         _result = value_cast<const StringValue *>(toStringMember->call(object)); // ### invoke convert-to-string?
     }
 }
-
-////////////////////////////////////////////////////////////////////////////////
-// convert to object
-////////////////////////////////////////////////////////////////////////////////
-void ConvertToObject::visit(const NullValue *value)
-{
-    _result = value;
-}
-
-void ConvertToObject::visit(const UndefinedValue *)
-{
-    _result = _engine->nullValue();
-}
-
-void ConvertToObject::visit(const NumberValue *)
-{
-    _result = _engine->call(_engine->numberCtor());
-}
-
-void ConvertToObject::visit(const BooleanValue *)
-{
-    _result = _engine->call(_engine->booleanCtor());
-}
-
-void ConvertToObject::visit(const StringValue *)
-{
-    _result = _engine->call(_engine->stringCtor());
-}
-
-void ConvertToObject::visit(const ObjectValue *object)
-{
-    _result = object;
-}
-
-void ConvertToObject::visit(const FunctionValue *object)
-{
-    _result = object;
-}
-
diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp
index dfc3d11bf82750c0310441ddd06a592a05792562..005ea17cc36af45e78c0419f9b90f6fffa4c8173 100644
--- a/src/plugins/qmljseditor/qmlcodecompletion.cpp
+++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp
@@ -30,13 +30,13 @@
 #include "qmlcodecompletion.h"
 #include "qmljseditor.h"
 #include "qmlmodelmanagerinterface.h"
-#include "qmlexpressionundercursor.h"
 #include "qmllookupcontext.h"
-#include "qmlresolveexpression.h"
 
 #include <qmljs/parser/qmljsast_p.h>
 #include <qmljs/qmljsinterpreter.h>
 #include <qmljs/qmljssymbol.h>
+#include <qmljs/qmljsscanner.h>
+
 #include <texteditor/basetexteditor.h>
 
 #include <coreplugin/icore.h>
@@ -94,7 +94,102 @@ static QIcon iconForColor(const QColor &color)
 
 namespace {
 
-class Evaluate: public QmlJS::AST::Visitor
+class ExpressionUnderCursor
+{
+    QTextCursor _cursor;
+    QmlJSScanner scanner;
+
+public:
+    QString operator()(const QTextCursor &cursor)
+    {
+        _cursor = cursor;
+
+        QTextBlock block = _cursor.block();
+        const QString blockText = block.text().left(cursor.columnNumber());
+        //qDebug() << "block text:" << blockText;
+
+        int startState = block.previous().userState();
+        if (startState == -1)
+            startState = 0;
+        else
+            startState = startState & 0xff;
+
+        const QList<Token> originalTokens = scanner(blockText, startState);
+        QList<Token> tokens;
+        int skipping = 0;
+        for (int index = originalTokens.size() - 1; index != -1; --index) {
+            const Token &tk = originalTokens.at(index);
+
+            if (tk.is(Token::Comment) || tk.is(Token::String) || tk.is(Token::Number))
+                continue;
+
+            if (! skipping) {
+                tokens.append(tk);
+
+                if (tk.is(Token::Identifier)) {
+                    if (index > 0 && originalTokens.at(index - 1).isNot(Token::Dot))
+                        break;
+                }
+            } else {
+                //qDebug() << "skip:" << blockText.mid(tk.offset, tk.length);
+            }
+
+            if (tk.is(Token::RightParenthesis))
+                ++skipping;
+
+            else if (tk.is(Token::LeftParenthesis)) {
+                --skipping;
+
+                if (! skipping)
+                    tokens.append(tk);
+            }
+        }
+
+        if (! tokens.isEmpty()) {
+            QString expr;
+            for (int index = tokens.size() - 1; index >= 0; --index) {
+                Token tk = tokens.at(index);
+                expr.append(QLatin1Char(' '));
+                expr.append(blockText.midRef(tk.offset, tk.length));
+            }
+
+            //qDebug() << "expression under cursor:" << expr;
+            return expr;
+        }
+
+        //qDebug() << "no expression";
+        return QString();
+    }
+};
+
+class SearchPropertyDefinitions: protected AST::Visitor
+{
+    QList<AST::UiPublicMember *> _properties;
+
+public:
+    QList<AST::UiPublicMember *> operator()(AST::Node *node)
+    {
+        _properties.clear();
+        if (node)
+            node->accept(this);
+        return _properties;
+    }
+
+
+protected:
+    using AST::Visitor::visit;
+
+    virtual bool visit(AST::UiPublicMember *member)
+    {
+        if (member->propertyToken.isValid()) {
+            _properties.append(member);
+        }
+
+        return true;
+    }
+};
+
+class Evaluate: protected QmlJS::AST::Visitor
 {
     QmlJS::Interpreter::Engine *_interp;
     const QmlJS::Interpreter::Value *_value;
@@ -127,17 +222,20 @@ protected:
         return previousValue;
     }
 
-    virtual bool preVisit(QmlJS::AST::Node *ast)
+    virtual bool preVisit(QmlJS::AST::Node *ast) // ### remove me
     {
         using namespace QmlJS::AST;
 
         if (cast<NumericLiteral *>(ast))
             return true;
 
-        if (cast<StringLiteral *>(ast))
+        else if (cast<StringLiteral *>(ast))
             return true;
 
-        if (cast<IdentifierExpression *>(ast))
+        else if (cast<IdentifierExpression *>(ast))
+            return true;
+
+        else if (cast<NestedExpression *>(ast))
             return true;
 
         else if (cast<FieldMemberExpression *>(ast))
@@ -149,6 +247,11 @@ protected:
         return false;
     }
 
+    virtual bool visit(QmlJS::AST::NestedExpression *)
+    {
+        return true;
+    }
+
     virtual bool visit(QmlJS::AST::StringLiteral *)
     {
         _value = _interp->convertToObject(_interp->stringValue());
@@ -163,13 +266,19 @@ protected:
 
     virtual bool visit(QmlJS::AST::IdentifierExpression *ast)
     {
+        if (! ast->name)
+            return false;
+
         _value = _interp->globalObject()->property(ast->name->asString());
         return false;
     }
 
     virtual bool visit(QmlJS::AST::FieldMemberExpression *ast)
     {
-        if (const QmlJS::Interpreter::Value *base = evaluate(ast->base)) {
+        if (! ast->name)
+            return false;
+
+        if (const QmlJS::Interpreter::Value *base = _interp->convertToObject(evaluate(ast->base))) {
             if (const QmlJS::Interpreter::ObjectValue *obj = base->asObjectValue()) {
                 _value = obj->property(ast->name->asString());
             }
@@ -366,30 +475,28 @@ void FunctionArgumentWidget::updateArgumentHighlight()
     updateHintText();
 
 
-#if 0
     QString str = m_editor->textAt(m_startpos, curpos - m_startpos);
     int argnr = 0;
     int parcount = 0;
-    SimpleLexer tokenize;
-    QList<SimpleToken> tokens = tokenize(str);
+    QmlJSScanner tokenize;
+    const QList<Token> tokens = tokenize(str);
     for (int i = 0; i < tokens.count(); ++i) {
-        const SimpleToken &tk = tokens.at(i);
-        if (tk.is(T_LPAREN))
+        const Token &tk = tokens.at(i);
+        if (tk.is(Token::LeftParenthesis))
             ++parcount;
-        else if (tk.is(T_RPAREN))
+        else if (tk.is(Token::RightParenthesis))
             --parcount;
-        else if (! parcount && tk.is(T_COMMA))
+        else if (! parcount && tk.is(Token::Colon))
             ++argnr;
     }
 
     if (m_currentarg != argnr) {
-        m_currentarg = argnr;
+        // m_currentarg = argnr;
         updateHintText();
     }
 
     if (parcount < 0)
         m_popupFrame->close();
-#endif
 }
 
 bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e)
@@ -511,12 +618,11 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
     if (! edit)
         return -1;
 
-    int pos = editor->position();
+    m_startPosition = editor->position();
 
-    while (editor->characterAt(pos - 1).isLetterOrNumber() || editor->characterAt(pos - 1) == QLatin1Char('_'))
-        --pos;
+    while (editor->characterAt(m_startPosition - 1).isLetterOrNumber() || editor->characterAt(m_startPosition - 1) == QLatin1Char('_'))
+        --m_startPosition;
 
-    m_startPosition = pos;
     m_completions.clear();
 
     QmlJS::Document::Ptr qmlDocument = edit->qmlDocument();
@@ -579,20 +685,12 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
     }
 
     if (completionOperator == QLatin1Char('.') || completionOperator == QLatin1Char('(')) {
-        const int endOfExpression = m_startPosition - 1;
-        int startOfExpression = endOfExpression - 2;
+        ExpressionUnderCursor expressionUnderCursor;
 
-        while (startOfExpression >= 0) {
-            const QChar ch = editor->characterAt(startOfExpression);
+        QTextCursor tc = edit->textCursor();
+        tc.setPosition(m_startPosition - 1);
 
-            if (ch.isLetterOrNumber() || ch == QLatin1Char('_') || ch == QLatin1Char('.'))
-                --startOfExpression;
-            else
-                break;
-        }
-        ++startOfExpression;
-
-        const QString expression = m_editor->textAt(startOfExpression, endOfExpression - startOfExpression);
+        const QString expression = expressionUnderCursor(tc);
         //qDebug() << "expression:" << expression;
 
         QmlJS::Document::Ptr exprDoc = QmlJS::Document::create(QLatin1String("<expression>"));
@@ -603,6 +701,15 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
             Interpreter::Engine interp;
             Evaluate evaluate(&interp);
 
+            SearchPropertyDefinitions searchPropertyDefinitions;
+
+            const QList<AST::UiPublicMember *> properties = searchPropertyDefinitions(qmlDocument->ast());
+            foreach (AST::UiPublicMember *prop, properties) {
+                if (prop->name && prop->memberType && prop->memberType->asString() == QLatin1String("string")) {
+                    interp.globalObject()->setProperty(prop->name->asString(), interp.stringValue());
+                }
+            }
+
             const Interpreter::Value *value = interp.convertToObject(evaluate(exprDoc->ast()));
             //qDebug() << "type:" << interp.typeId(value);
 
@@ -619,20 +726,18 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
                     item.icon = symbolIcon;
                     m_completions.append(item);
                 }
-
             } else if (value && completionOperator == QLatin1Char('(')) {
                 if (const Interpreter::FunctionValue *f = value->asFunctionValue()) {
                     QString functionName = expression;
                     int indexOfDot = expression.lastIndexOf(QLatin1Char('.'));
                     if (indexOfDot != -1)
                         functionName = expression.mid(indexOfDot + 1);
+
                     // Recreate if necessary
                     if (!m_functionArgumentWidget)
                         m_functionArgumentWidget = new QmlJSEditor::Internal::FunctionArgumentWidget;
 
-                    m_functionArgumentWidget->showFunctionHint(functionName,
-                                                               f->argumentCount(),
-                                                               m_startPosition);
+                    m_functionArgumentWidget->showFunctionHint(functionName.trimmed(), f->argumentCount(), m_startPosition);
                 }
 
                 return -1;
@@ -655,7 +760,10 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
         m_completions.append(m_snippets);
     }
 
-    return pos;
+    if (! m_completions.isEmpty())
+        return m_startPosition;
+
+    return -1;
 }
 
 void QmlCodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)