Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Marco Bubke
flatpak-qt-creator
Commits
f7a077b1
Commit
f7a077b1
authored
Nov 12, 2010
by
Christian Kamm
Browse files
QmlJS: Avoid infinite loop with recursive prototypes.
parent
443be8ee
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/libs/qmljs/qmljsinterpreter.cpp
View file @
f7a077b1
...
...
@@ -1675,7 +1675,9 @@ void Context::setProperty(const ObjectValue *object, const QString &name, const
QString
Context
::
defaultPropertyName
(
const
ObjectValue
*
object
)
const
{
for
(
const
ObjectValue
*
o
=
object
;
o
;
o
=
o
->
prototype
(
this
))
{
PrototypeIterator
iter
(
object
,
this
);
while
(
iter
.
hasNext
())
{
const
ObjectValue
*
o
=
iter
.
next
();
if
(
const
ASTObjectValue
*
astObjValue
=
dynamic_cast
<
const
ASTObjectValue
*>
(
o
))
{
QString
defaultProperty
=
astObjValue
->
defaultPropertyName
();
if
(
!
defaultProperty
.
isEmpty
())
...
...
@@ -1881,9 +1883,11 @@ const Value *ObjectValue::lookupMember(const QString &name, const Context *conte
}
if
(
examinePrototypes
)
{
const
ObjectValue
*
prototypeObject
=
prototype
(
context
);
if
(
prototypeObject
)
{
if
(
const
Value
*
m
=
prototypeObject
->
lookupMember
(
name
,
context
))
PrototypeIterator
iter
(
this
,
context
);
iter
.
next
();
// skip this
while
(
iter
.
hasNext
())
{
const
ObjectValue
*
prototypeObject
=
iter
.
next
();
if
(
const
Value
*
m
=
prototypeObject
->
lookupMember
(
name
,
context
,
false
))
return
m
;
}
}
...
...
@@ -1891,6 +1895,55 @@ const Value *ObjectValue::lookupMember(const QString &name, const Context *conte
return
0
;
}
PrototypeIterator
::
PrototypeIterator
(
const
ObjectValue
*
start
,
const
Context
*
context
)
:
m_current
(
0
)
,
m_next
(
start
)
,
m_context
(
context
)
{
if
(
start
)
m_prototypes
.
reserve
(
10
);
}
bool
PrototypeIterator
::
hasNext
()
{
if
(
m_next
)
return
true
;
if
(
!
m_current
)
return
false
;
m_next
=
m_current
->
prototype
(
m_context
);
if
(
!
m_next
||
m_prototypes
.
contains
(
m_next
))
{
m_next
=
0
;
return
false
;
}
return
true
;
}
const
ObjectValue
*
PrototypeIterator
::
next
()
{
if
(
hasNext
())
{
m_current
=
m_next
;
m_prototypes
+=
m_next
;
m_next
=
0
;
return
m_current
;
}
return
0
;
}
const
ObjectValue
*
PrototypeIterator
::
peekNext
()
{
if
(
hasNext
())
{
return
m_next
;
}
return
0
;
}
QList
<
const
ObjectValue
*>
PrototypeIterator
::
all
()
{
while
(
hasNext
())
next
();
return
m_prototypes
;
}
Activation
::
Activation
(
Context
*
parentContext
)
:
_thisObject
(
0
),
_calledAsFunction
(
true
),
...
...
src/libs/qmljs/qmljsinterpreter.h
View file @
f7a077b1
...
...
@@ -397,6 +397,7 @@ public:
QString
className
()
const
;
void
setClassName
(
const
QString
&
className
);
// not guaranteed to not recurse, use PrototypeIterator!
const
ObjectValue
*
prototype
(
const
Context
*
context
)
const
;
void
setPrototype
(
const
Value
*
prototype
);
...
...
@@ -422,6 +423,24 @@ private:
QString
_className
;
};
class
QMLJS_EXPORT
PrototypeIterator
{
public:
PrototypeIterator
(
const
ObjectValue
*
start
,
const
Context
*
context
);
bool
hasNext
();
const
ObjectValue
*
peekNext
();
const
ObjectValue
*
next
();
QList
<
const
ObjectValue
*>
all
();
private:
const
ObjectValue
*
m_current
;
const
ObjectValue
*
m_next
;
QList
<
const
ObjectValue
*>
m_prototypes
;
const
Context
*
m_context
;
};
class
QMLJS_EXPORT
QmlObjectValue
:
public
ObjectValue
{
public:
...
...
src/libs/qmljs/qmljsscopebuilder.cpp
View file @
f7a077b1
...
...
@@ -202,8 +202,10 @@ void ScopeBuilder::setQmlScopeObject(Node *node)
// check if the object has a Qt.ListElement or Qt.Connections ancestor
// ### allow only signal bindings for Connections
const
ObjectValue
*
prototype
=
scopeObject
->
prototype
(
_context
);
while
(
prototype
)
{
PrototypeIterator
iter
(
scopeObject
,
_context
);
iter
.
next
();
while
(
iter
.
hasNext
())
{
const
ObjectValue
*
prototype
=
iter
.
next
();
if
(
const
QmlObjectValue
*
qmlMetaObject
=
dynamic_cast
<
const
QmlObjectValue
*>
(
prototype
))
{
if
((
qmlMetaObject
->
className
()
==
QLatin1String
(
"ListElement"
)
||
qmlMetaObject
->
className
()
==
QLatin1String
(
"Connections"
)
...
...
@@ -213,11 +215,10 @@ void ScopeBuilder::setQmlScopeObject(Node *node)
break
;
}
}
prototype
=
prototype
->
prototype
(
_context
);
}
// check if the object has a Qt.PropertyChanges ancestor
prototype
=
scopeObject
->
prototype
(
_context
);
const
ObjectValue
*
prototype
=
scopeObject
->
prototype
(
_context
);
prototype
=
isPropertyChangesObject
(
_context
,
prototype
);
// find the target script binding
if
(
prototype
)
{
...
...
@@ -281,15 +282,15 @@ const Value *ScopeBuilder::scopeObjectLookup(AST::UiQualifiedId *id)
const
ObjectValue
*
ScopeBuilder
::
isPropertyChangesObject
(
const
Context
*
context
,
const
ObjectValue
*
object
)
{
const
ObjectValue
*
prototype
=
object
;
while
(
prototype
)
{
PrototypeIterator
iter
(
object
,
context
);
while
(
iter
.
hasNext
())
{
const
ObjectValue
*
prototype
=
iter
.
next
();
if
(
const
QmlObjectValue
*
qmlMetaObject
=
dynamic_cast
<
const
QmlObjectValue
*>
(
prototype
))
{
if
(
qmlMetaObject
->
className
()
==
QLatin1String
(
"PropertyChanges"
)
&&
(
qmlMetaObject
->
packageName
()
==
QLatin1String
(
"Qt"
)
||
qmlMetaObject
->
packageName
()
==
QLatin1String
(
"QtQuick"
)))
return
prototype
;
}
prototype
=
prototype
->
prototype
(
context
);
}
return
0
;
}
src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
View file @
f7a077b1
...
...
@@ -372,10 +372,12 @@ public:
if
(
objectValue
&&
objectValue
->
prototype
(
m_context
)
==
m_context
->
engine
()
->
arrayPrototype
())
return
true
;
for
(
const
Interpreter
::
ObjectValue
*
iter
=
containingObject
;
iter
;
iter
=
iter
->
prototype
(
m_context
))
{
if
(
iter
->
property
(
name
,
m_context
)
==
m_context
->
engine
()
->
arrayPrototype
())
Interpreter
::
PrototypeIterator
iter
(
containingObject
,
m_context
);
while
(
iter
.
hasNext
())
{
const
Interpreter
::
ObjectValue
*
proto
=
iter
.
next
();
if
(
proto
->
property
(
name
,
m_context
)
==
m_context
->
engine
()
->
arrayPrototype
())
return
true
;
if
(
const
Interpreter
::
QmlObjectValue
*
qmlIter
=
dynamic_cast
<
const
Interpreter
::
QmlObjectValue
*>
(
iter
))
{
if
(
const
Interpreter
::
QmlObjectValue
*
qmlIter
=
dynamic_cast
<
const
Interpreter
::
QmlObjectValue
*>
(
proto
))
{
if
(
qmlIter
->
isListProperty
(
name
))
return
true
;
}
...
...
@@ -397,9 +399,11 @@ public:
return
hasQuotes
?
QVariant
(
cleanedValue
)
:
cleverConvert
(
cleanedValue
);
}
for
(
const
Interpreter
::
ObjectValue
*
iter
=
containingObject
;
iter
;
iter
=
iter
->
prototype
(
m_context
))
{
if
(
iter
->
lookupMember
(
name
,
m_context
,
false
))
{
containingObject
=
iter
;
Interpreter
::
PrototypeIterator
iter
(
containingObject
,
m_context
);
while
(
iter
.
hasNext
())
{
const
Interpreter
::
ObjectValue
*
proto
=
iter
.
next
();
if
(
proto
->
lookupMember
(
name
,
m_context
,
false
))
{
containingObject
=
proto
;
break
;
}
}
...
...
@@ -446,9 +450,11 @@ public:
return
QVariant
();
}
for
(
const
Interpreter
::
ObjectValue
*
iter
=
containingObject
;
iter
;
iter
=
iter
->
prototype
(
m_context
))
{
if
(
iter
->
lookupMember
(
name
,
m_context
,
false
))
{
containingObject
=
iter
;
Interpreter
::
PrototypeIterator
iter
(
containingObject
,
m_context
);
while
(
iter
.
hasNext
())
{
const
Interpreter
::
ObjectValue
*
proto
=
iter
.
next
();
if
(
proto
->
lookupMember
(
name
,
m_context
,
false
))
{
containingObject
=
proto
;
break
;
}
}
...
...
@@ -473,12 +479,11 @@ public:
rhsValueName
=
memberExp
->
name
->
asString
();
}
if
(
!
rhsValueObject
)
return
QVariant
();
for
(
const
Interpreter
::
ObjectValue
*
iter
=
rhsValueObject
;
iter
;
iter
=
iter
->
prototype
(
m_context
))
{
if
(
iter
->
lookupMember
(
rhsValueName
,
m_context
,
false
))
{
rhsValueObject
=
iter
;
iter
=
Interpreter
::
PrototypeIterator
(
rhsValueObject
,
m_context
);
while
(
iter
.
hasNext
())
{
const
Interpreter
::
ObjectValue
*
proto
=
iter
.
next
();
if
(
proto
->
lookupMember
(
rhsValueName
,
m_context
,
false
))
{
rhsValueObject
=
proto
;
break
;
}
}
...
...
src/plugins/qmljseditor/qmljseditor.cpp
View file @
f7a077b1
...
...
@@ -1055,11 +1055,13 @@ protected:
{
Bind
*
bind
=
m_lookupContext
->
document
()
->
bind
();
const
Interpreter
::
ObjectValue
*
objValue
=
bind
->
findQmlObject
(
ast
);
QStringList
prototypes
;
if
(
!
objValue
)
return
false
;
while
(
objValue
)
{
prototypes
.
append
(
objValue
->
className
());
objValue
=
objValue
->
prototype
(
m_lookupContext
->
context
());
QStringList
prototypes
;
foreach
(
const
Interpreter
::
ObjectValue
*
value
,
Interpreter
::
PrototypeIterator
(
objValue
,
m_lookupContext
->
context
()).
all
())
{
prototypes
.
append
(
value
->
className
());
}
return
prototypes
.
contains
(
QString
(
"QGraphicsObject"
));
...
...
src/plugins/qmljseditor/qmljsfindreferences.cpp
View file @
f7a077b1
...
...
@@ -71,12 +71,16 @@ static const ObjectValue *prototypeWithMember(const Context *context, const Obje
const
Value
*
value
=
object
->
property
(
name
,
context
);
if
(
!
value
)
return
0
;
forever
{
const
ObjectValue
*
prototype
=
object
->
prototype
(
context
);
if
(
!
prototype
||
prototype
->
property
(
name
,
context
)
!=
value
)
return
object
;
object
=
prototype
;
}
const
ObjectValue
*
prev
=
object
;
PrototypeIterator
iter
(
object
,
context
);
iter
.
next
();
while
(
iter
.
hasNext
())
{
const
ObjectValue
*
prototype
=
iter
.
next
();
if
(
prototype
->
property
(
name
,
context
)
!=
value
)
return
prev
;
prev
=
prototype
;
}
return
prev
;
}
namespace
{
...
...
src/plugins/qmljseditor/qmljshoverhandler.cpp
View file @
f7a077b1
...
...
@@ -237,17 +237,19 @@ void HoverHandler::prettyPrintTooltip(const QmlJS::Interpreter::Value *value,
if
(
const
Interpreter
::
ObjectValue
*
objectValue
=
value
->
asObjectValue
())
{
bool
found
=
false
;
do
{
const
QString
className
=
objectValue
->
className
();
Interpreter
::
PrototypeIterator
iter
(
objectValue
,
context
);
while
(
iter
.
hasNext
())
{
const
Interpreter
::
ObjectValue
*
prototype
=
iter
.
next
();
const
QString
className
=
prototype
->
className
();
if
(
!
className
.
isEmpty
())
{
found
=
!
qmlHelpId
(
className
).
isEmpty
();
if
(
toolTip
().
isEmpty
()
||
found
)
setToolTip
(
className
);
}
objectValue
=
objectValue
->
prototype
(
context
)
;
}
while
(
objectValue
&&
!
found
);
if
(
found
)
break
;
}
}
else
if
(
const
Interpreter
::
QmlEnumValue
*
enumValue
=
dynamic_cast
<
const
Interpreter
::
QmlEnumValue
*>
(
value
))
{
setToolTip
(
enumValue
->
name
());
...
...
src/plugins/qmljseditor/quicktoolbar.cpp
View file @
f7a077b1
...
...
@@ -115,19 +115,21 @@ void QuickToolBar::apply(TextEditor::BaseTextEditorEditable *editor, Document::P
const
Interpreter
::
ObjectValue
*
scopeObject
=
document
->
bind
()
->
findQmlObject
(
node
);
if
(
!
lookupContext
.
isNull
())
{
if
(
!
lookupContext
.
isNull
()
&&
scopeObject
)
{
m_prototypes
.
clear
();
while
(
s
co
peObject
)
{
m_prototypes
.
append
(
scopeObject
->
className
())
;
scopeObject
=
scopeObject
->
prototype
(
lookupContext
->
context
());
foreach
(
co
nst
Interpreter
::
ObjectValue
*
object
,
Interpreter
::
PrototypeIterator
(
scopeObject
,
lookupContext
->
context
()).
all
())
{
m_prototypes
.
append
(
object
->
className
());
}
if
(
m_prototypes
.
contains
(
"PropertyChanges"
))
{
const
Interpreter
::
ObjectValue
*
targetObject
=
getPropertyChangesTarget
(
node
,
lookupContext
);
m_prototypes
.
clear
();
while
(
targetObject
)
{
m_prototypes
.
append
(
targetObject
->
className
());
targetObject
=
targetObject
->
prototype
(
lookupContext
->
context
());
if
(
targetObject
)
{
foreach
(
const
Interpreter
::
ObjectValue
*
object
,
Interpreter
::
PrototypeIterator
(
targetObject
,
lookupContext
->
context
()).
all
())
{
m_prototypes
.
append
(
object
->
className
());
}
}
}
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment