From 7b2110de7ea69ffa3914d3289ac42cbb69d9a414 Mon Sep 17 00:00:00 2001
From: Christian Kamm <christian.d.kamm@nokia.com>
Date: Mon, 12 Sep 2011 11:48:33 +0200
Subject: [PATCH] QmlJS: Fix reference lookup cycles.

Since several reference lookups involve Evaluate which may cause
further reference lookups, we need to be able to pass the existing
ReferenceContext to avoid cycles.

Change-Id: I2f1eeaad4d6b6ff094413d51077b03c985f6fab4
Reviewed-on: http://codereview.qt-project.org/4653
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
---
 src/libs/qmljs/qmljsevaluate.cpp    | 11 ++++++++---
 src/libs/qmljs/qmljsevaluate.h      |  3 ++-
 src/libs/qmljs/qmljsinterpreter.cpp | 14 +++++++-------
 src/libs/qmljs/qmljsinterpreter.h   | 10 +++++-----
 4 files changed, 22 insertions(+), 16 deletions(-)

diff --git a/src/libs/qmljs/qmljsevaluate.cpp b/src/libs/qmljs/qmljsevaluate.cpp
index 5c3ecfa1d45..80680d7b2ed 100644
--- a/src/libs/qmljs/qmljsevaluate.cpp
+++ b/src/libs/qmljs/qmljsevaluate.cpp
@@ -39,9 +39,10 @@
 
 using namespace QmlJS;
 
-Evaluate::Evaluate(const ScopeChain *scopeChain)
+Evaluate::Evaluate(const ScopeChain *scopeChain, ReferenceContext *referenceContext)
     : _valueOwner(scopeChain->context()->valueOwner()),
       _context(scopeChain->context()),
+      _referenceContext(referenceContext),
       _scopeChain(scopeChain),
       _scope(_valueOwner->globalObject()),
       _result(0)
@@ -61,8 +62,12 @@ const Value *Evaluate::value(AST::Node *ast)
 {
     const Value *result = reference(ast);
 
-    if (const Reference *ref = value_cast<const Reference *>(result))
-        result = _context->lookupReference(ref);
+    if (const Reference *ref = value_cast<const Reference *>(result)) {
+        if (_referenceContext)
+            result = _referenceContext->lookupReference(ref);
+        else
+            result = _context->lookupReference(ref);
+    }
 
     if (! result)
         result = _valueOwner->undefinedValue();
diff --git a/src/libs/qmljs/qmljsevaluate.h b/src/libs/qmljs/qmljsevaluate.h
index a3289465608..62271459687 100644
--- a/src/libs/qmljs/qmljsevaluate.h
+++ b/src/libs/qmljs/qmljsevaluate.h
@@ -48,7 +48,7 @@ class FunctionValue;
 class QMLJS_EXPORT Evaluate: protected AST::Visitor
 {
 public:
-    Evaluate(const ScopeChain *scopeChain);
+    Evaluate(const ScopeChain *scopeChain, ReferenceContext *referenceContext = 0);
     virtual ~Evaluate();
 
     // same as value()
@@ -164,6 +164,7 @@ private:
     QmlJS::Document::Ptr _doc;
     ValueOwner *_valueOwner;
     ContextPtr _context;
+    ReferenceContext *_referenceContext;
     const ScopeChain *_scopeChain;
     const ObjectValue *_scope;
     const Value *_result;
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index a8cfb6e9748..f288c36ed2b 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -727,7 +727,7 @@ void Reference::accept(ValueVisitor *visitor) const
     visitor->visit(this);
 }
 
-const Value *Reference::value(const ReferenceContext *) const
+const Value *Reference::value(ReferenceContext *) const
 {
     return _valueOwner->undefinedValue();
 }
@@ -1745,7 +1745,7 @@ ASTVariableReference::~ASTVariableReference()
 {
 }
 
-const Value *ASTVariableReference::value(const ReferenceContext *referenceContext) const
+const Value *ASTVariableReference::value(ReferenceContext *referenceContext) const
 {
     if (!_ast->expression)
         return valueOwner()->undefinedValue();
@@ -1755,7 +1755,7 @@ const Value *ASTVariableReference::value(const ReferenceContext *referenceContex
     ScopeBuilder builder(&scopeChain);
     builder.push(ScopeAstPath(doc)(_ast->expression->firstSourceLocation().begin()));
 
-    Evaluate evaluator(&scopeChain);
+    Evaluate evaluator(&scopeChain, referenceContext);
     return evaluator(_ast->expression);
 }
 
@@ -1832,7 +1832,7 @@ UiQualifiedId *QmlPrototypeReference::qmlTypeName() const
     return _qmlTypeName;
 }
 
-const Value *QmlPrototypeReference::value(const ReferenceContext *referenceContext) const
+const Value *QmlPrototypeReference::value(ReferenceContext *referenceContext) const
 {
     return referenceContext->context()->lookupType(_doc, _qmlTypeName);
 }
@@ -1859,7 +1859,7 @@ bool ASTPropertyReference::getSourceLocation(QString *fileName, int *line, int *
     return true;
 }
 
-const Value *ASTPropertyReference::value(const ReferenceContext *referenceContext) const
+const Value *ASTPropertyReference::value(ReferenceContext *referenceContext) const
 {
     if (_ast->statement
             && (!_ast->memberType || _ast->memberType->asString() == QLatin1String("variant")
@@ -1875,7 +1875,7 @@ const Value *ASTPropertyReference::value(const ReferenceContext *referenceContex
         int offset = _ast->statement->firstSourceLocation().begin();
         builder.push(ScopeAstPath(doc)(offset));
 
-        Evaluate evaluator(&scopeChain);
+        Evaluate evaluator(&scopeChain, referenceContext);
         return evaluator(_ast->statement);
     }
 
@@ -1906,7 +1906,7 @@ bool ASTSignalReference::getSourceLocation(QString *fileName, int *line, int *co
     return true;
 }
 
-const Value *ASTSignalReference::value(const ReferenceContext *) const
+const Value *ASTSignalReference::value(ReferenceContext *) const
 {
     return valueOwner()->undefinedValue();
 }
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index cc7999739b9..2fad1f43a0d 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -296,7 +296,7 @@ public:
     virtual void accept(ValueVisitor *) const;
 
 private:
-    virtual const Value *value(const ReferenceContext *referenceContext) const;
+    virtual const Value *value(ReferenceContext *referenceContext) const;
 
     ValueOwner *_valueOwner;
     friend class ReferenceContext;
@@ -699,7 +699,7 @@ public:
     AST::UiQualifiedId *qmlTypeName() const;
 
 private:    
-    virtual const Value *value(const ReferenceContext *referenceContext) const;
+    virtual const Value *value(ReferenceContext *referenceContext) const;
 
     AST::UiQualifiedId *_qmlTypeName;
     const Document *_doc;
@@ -715,7 +715,7 @@ public:
     virtual ~ASTVariableReference();
 
 private:
-    virtual const Value *value(const ReferenceContext *referenceContext) const;
+    virtual const Value *value(ReferenceContext *referenceContext) const;
 };
 
 class QMLJS_EXPORT ASTFunctionValue: public FunctionValue
@@ -755,7 +755,7 @@ public:
     virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
 
 private:
-    virtual const Value *value(const ReferenceContext *referenceContext) const;
+    virtual const Value *value(ReferenceContext *referenceContext) const;
 };
 
 class QMLJS_EXPORT ASTSignalReference: public Reference
@@ -774,7 +774,7 @@ public:
     virtual bool getSourceLocation(QString *fileName, int *line, int *column) const;
 
 private:
-    virtual const Value *value(const ReferenceContext *referenceContext) const;
+    virtual const Value *value(ReferenceContext *referenceContext) const;
 };
 
 class QMLJS_EXPORT ASTObjectValue: public ObjectValue
-- 
GitLab