forked from qt-creator/qt-creator
QmlJS: Refactor LookupContext creation for speed.
* If possible, create LookupContexts through SemanticInfo; it caches the linked Context and will be faster. * Contexts now own their Engine. Reviewed-by: Lasse Holmstedt
This commit is contained in:
@@ -691,7 +691,7 @@ int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
|
||||
const QIcon keywordIcon = iconForColor(Qt::darkYellow);
|
||||
|
||||
const QList<AST::Node *> path = semanticInfo.astPath(editor->position());
|
||||
LookupContext::Ptr lookupContext = LookupContext::create(document, snapshot, path);
|
||||
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(path);
|
||||
const Interpreter::Context *context = lookupContext->context();
|
||||
|
||||
// Search for the operator that triggered the completion.
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
#include <qmljs/qmljsicontextpane.h>
|
||||
#include <qmljs/qmljslookupcontext.h>
|
||||
#include <qmljs/qmljslink.h>
|
||||
#include <qmljs/parser/qmljsastvisitor_p.h>
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <qmljs/parser/qmljsengine_p.h>
|
||||
@@ -553,6 +554,18 @@ QList<AST::Node *> SemanticInfo::astPath(int cursorPosition) const
|
||||
return path;
|
||||
}
|
||||
|
||||
LookupContext::Ptr SemanticInfo::lookupContext(const QList<QmlJS::AST::Node *> &path) const
|
||||
{
|
||||
// create and link context if necessary
|
||||
if (!m_context) {
|
||||
Interpreter::Context *ctx = new Interpreter::Context;
|
||||
Link link(ctx, document, snapshot, ModelManagerInterface::instance()->importPaths());
|
||||
m_context = QSharedPointer<const QmlJS::Interpreter::Context>(ctx);
|
||||
}
|
||||
|
||||
return LookupContext::create(document, snapshot, *m_context, path);
|
||||
}
|
||||
|
||||
static bool importContainsCursor(UiImport *importAst, unsigned cursorPosition)
|
||||
{
|
||||
return cursorPosition >= importAst->firstSourceLocation().begin()
|
||||
@@ -962,9 +975,9 @@ void QmlJSTextEditor::updateCursorPositionNow()
|
||||
Node *oldNode = m_semanticInfo.declaringMemberNoProperties(m_oldCursorPosition);
|
||||
Node *newNode = m_semanticInfo.declaringMemberNoProperties(position());
|
||||
if (oldNode != newNode && m_oldCursorPosition != -1)
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, m_semanticInfo.snapshot, newNode, false);
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.lookupContext(), newNode, false);
|
||||
if (oldNode != newNode &&
|
||||
m_contextPane->isAvailable(editableInterface(), m_semanticInfo.document, m_semanticInfo.snapshot, newNode) &&
|
||||
m_contextPane->isAvailable(editableInterface(), m_semanticInfo.lookupContext(), newNode) &&
|
||||
!m_contextPane->widget()->isVisible()) {
|
||||
QList<TextEditor::Internal::RefactorMarker> markers;
|
||||
if (UiObjectMember *m = newNode->uiObjectMemberCast()) {
|
||||
@@ -1042,22 +1055,19 @@ class SelectedElement: protected Visitor
|
||||
unsigned m_cursorPositionStart;
|
||||
unsigned m_cursorPositionEnd;
|
||||
QList<UiObjectMember *> m_selectedMembers;
|
||||
Document::Ptr m_document;
|
||||
Snapshot m_snapshot;
|
||||
LookupContext::Ptr m_lookupContext;
|
||||
|
||||
public:
|
||||
SelectedElement()
|
||||
: m_cursorPositionStart(0), m_cursorPositionEnd(0) {}
|
||||
|
||||
QList<UiObjectMember *> operator()(Document::Ptr doc, Snapshot snapshot, unsigned startPosition, unsigned endPosition)
|
||||
QList<UiObjectMember *> operator()(LookupContext::Ptr lookupContext, unsigned startPosition, unsigned endPosition)
|
||||
{
|
||||
m_document = doc;
|
||||
m_snapshot = snapshot;
|
||||
m_lookupContext = lookupContext;
|
||||
m_cursorPositionStart = startPosition;
|
||||
m_cursorPositionEnd = endPosition;
|
||||
m_selectedMembers.clear();
|
||||
Node::accept(doc->qmlProgram(), this);
|
||||
Node::accept(lookupContext->document()->qmlProgram(), this);
|
||||
return m_selectedMembers;
|
||||
}
|
||||
|
||||
@@ -1092,14 +1102,10 @@ protected:
|
||||
|
||||
inline bool hasVisualPresentation(Node *ast)
|
||||
{
|
||||
Bind *bind = m_document->bind();
|
||||
Bind *bind = m_lookupContext->document()->bind();
|
||||
const Interpreter::ObjectValue *objValue = bind->findQmlObject(ast);
|
||||
QStringList prototypes;
|
||||
|
||||
if (m_lookupContext.isNull()) {
|
||||
m_lookupContext = LookupContext::create(m_document, m_snapshot, QList<Node*>());
|
||||
}
|
||||
|
||||
while (objValue) {
|
||||
prototypes.append(objValue->className());
|
||||
objValue = objValue->prototype(m_lookupContext->context());
|
||||
@@ -1189,7 +1195,7 @@ void QmlJSTextEditor::setSelectedElements()
|
||||
|
||||
if (m_semanticInfo.document) {
|
||||
SelectedElement selectedMembers;
|
||||
QList<UiObjectMember *> members = selectedMembers(m_semanticInfo.document, m_semanticInfo.snapshot,
|
||||
QList<UiObjectMember *> members = selectedMembers(m_semanticInfo.lookupContext(),
|
||||
startPos, endPos);
|
||||
if (!members.isEmpty()) {
|
||||
foreach(UiObjectMember *m, members) {
|
||||
@@ -1376,7 +1382,7 @@ TextEditor::BaseTextEditor::Link QmlJSTextEditor::findLinkAt(const QTextCursor &
|
||||
return Link();
|
||||
}
|
||||
|
||||
LookupContext::Ptr lookupContext = LookupContext::create(semanticInfo.document, semanticInfo.snapshot, semanticInfo.astPath(cursorPosition));
|
||||
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(semanticInfo.astPath(cursorPosition));
|
||||
const Interpreter::Value *value = lookupContext->evaluate(node);
|
||||
|
||||
QString fileName;
|
||||
@@ -1422,7 +1428,7 @@ void QmlJSTextEditor::showContextPane()
|
||||
{
|
||||
if (m_contextPane) {
|
||||
Node *newNode = m_semanticInfo.declaringMemberNoProperties(position());
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, m_semanticInfo.snapshot, newNode, false, true);
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.lookupContext(), newNode, false, true);
|
||||
m_oldCursorPosition = position();
|
||||
QList<TextEditor::Internal::RefactorMarker> markers;
|
||||
setRefactorMarkers(markers);
|
||||
@@ -1481,7 +1487,7 @@ void QmlJSTextEditor::wheelEvent(QWheelEvent *event)
|
||||
BaseTextEditor::wheelEvent(event);
|
||||
|
||||
if (visible)
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, m_semanticInfo.snapshot, m_semanticInfo.declaringMemberNoProperties(position()), false, true);
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.lookupContext(), m_semanticInfo.declaringMemberNoProperties(position()), false, true);
|
||||
}
|
||||
|
||||
void QmlJSTextEditor::resizeEvent(QResizeEvent *event)
|
||||
@@ -1723,7 +1729,7 @@ void QmlJSTextEditor::updateSemanticInfo(const SemanticInfo &semanticInfo)
|
||||
if (m_contextPane) {
|
||||
Node *newNode = m_semanticInfo.declaringMemberNoProperties(position());
|
||||
if (newNode) {
|
||||
m_contextPane->apply(editableInterface(), doc, m_semanticInfo.snapshot, newNode, true);
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.lookupContext(), newNode, true);
|
||||
showTextMarker();
|
||||
}
|
||||
}
|
||||
@@ -1776,7 +1782,7 @@ bool QmlJSTextEditor::hideContextPane()
|
||||
{
|
||||
bool b = (m_contextPane) && m_contextPane->widget()->isVisible();
|
||||
if (b)
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.document, m_semanticInfo.snapshot, 0, false);
|
||||
m_contextPane->apply(editableInterface(), m_semanticInfo.lookupContext(), 0, false);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
#include <qmljs/qmljsscanner.h>
|
||||
#include <qmljs/qmljsinterpreter.h>
|
||||
#include <texteditor/basetexteditor.h>
|
||||
|
||||
#include <QtCore/QWaitCondition>
|
||||
@@ -53,6 +54,7 @@ class ICore;
|
||||
namespace QmlJS {
|
||||
class ModelManagerInterface;
|
||||
class IContextPane;
|
||||
class LookupContext;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -129,6 +131,9 @@ public:
|
||||
// Returns the list of nodes that enclose the given position.
|
||||
QList<QmlJS::AST::Node *> astPath(int cursorPosition) const;
|
||||
|
||||
// Returns a context for the given path
|
||||
QSharedPointer<QmlJS::LookupContext> lookupContext(const QList<QmlJS::AST::Node *> &path = QList<QmlJS::AST::Node *>()) const;
|
||||
|
||||
public: // attributes
|
||||
QmlJS::Document::Ptr document;
|
||||
QmlJS::Snapshot snapshot;
|
||||
@@ -138,6 +143,10 @@ public: // attributes
|
||||
|
||||
// these are in addition to the parser messages in the document
|
||||
QList<QmlJS::DiagnosticMessage> semanticMessages;
|
||||
|
||||
private:
|
||||
// created lazily
|
||||
mutable QSharedPointer<const QmlJS::Interpreter::Context> m_context;
|
||||
};
|
||||
|
||||
class SemanticHighlighter: public QThread
|
||||
|
||||
@@ -111,9 +111,8 @@ void HoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos)
|
||||
if (astPath.isEmpty())
|
||||
return;
|
||||
|
||||
const Snapshot &snapshot = semanticInfo.snapshot;
|
||||
const Document::Ptr qmlDocument = semanticInfo.document;
|
||||
LookupContext::Ptr lookupContext = LookupContext::create(qmlDocument, snapshot, astPath);
|
||||
LookupContext::Ptr lookupContext = semanticInfo.lookupContext(astPath);
|
||||
|
||||
if (!matchColorItem(lookupContext, qmlDocument, astPath, pos))
|
||||
handleOrdinaryMatch(lookupContext, semanticInfo.nodeUnderCursor(pos));
|
||||
|
||||
@@ -42,10 +42,7 @@ QVariant QmlOutlineItem::data(int role) const
|
||||
return QVariant();
|
||||
|
||||
QList<AST::Node *> astPath = m_outlineModel->m_semanticInfo.astPath(location.begin());
|
||||
|
||||
Document::Ptr document = m_outlineModel->m_semanticInfo.document;
|
||||
Snapshot snapshot = m_outlineModel->m_semanticInfo.snapshot;
|
||||
LookupContext::Ptr lookupContext = LookupContext::create(document, snapshot, astPath);
|
||||
LookupContext::Ptr lookupContext = m_outlineModel->m_semanticInfo.lookupContext(astPath);
|
||||
const Interpreter::Value *value = lookupContext->evaluate(uiQualifiedId);
|
||||
|
||||
return prettyPrint(value, lookupContext->context());
|
||||
@@ -331,10 +328,9 @@ void QmlOutlineModel::update(const SemanticInfo &semanticInfo)
|
||||
|
||||
// Set up lookup context once to do the element type lookup
|
||||
//
|
||||
// We're simplifying here by using the root context everywhere
|
||||
// (empty node list). However, creating the LookupContext is quite expensive (about 3ms),
|
||||
// and there is AFAIK no way to introduce new type names in a sub-context.
|
||||
m_context = LookupContext::create(semanticInfo.document, semanticInfo.snapshot, QList<AST::Node*>());
|
||||
// We're simplifying here by using the root context everywhere; should be
|
||||
// ok since there is AFAIK no way to introduce new type names in a sub-context.
|
||||
m_context = semanticInfo.lookupContext();
|
||||
m_typeToIcon.clear();
|
||||
m_itemToNode.clear();
|
||||
m_itemToIdNode.clear();
|
||||
|
||||
@@ -98,13 +98,16 @@ QuickToolBar::~QuickToolBar()
|
||||
m_widget.clear();
|
||||
}
|
||||
|
||||
void QuickToolBar::apply(TextEditor::BaseTextEditorEditable *editor, Document::Ptr doc, const QmlJS::Snapshot &snapshot, AST::Node *node, bool update, bool force)
|
||||
void QuickToolBar::apply(TextEditor::BaseTextEditorEditable *editor, LookupContext::Ptr lookupContext, AST::Node *node, bool update, bool force)
|
||||
{
|
||||
if (!QuickToolBarSettings::get().enableContextPane && !force && !update) {
|
||||
contextWidget()->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (lookupContext.isNull())
|
||||
return;
|
||||
Document::Ptr doc = lookupContext->document();
|
||||
if (doc.isNull())
|
||||
return;
|
||||
|
||||
@@ -113,7 +116,6 @@ void QuickToolBar::apply(TextEditor::BaseTextEditorEditable *editor, Document::P
|
||||
|
||||
m_blockWriting = true;
|
||||
|
||||
LookupContext::Ptr lookupContext = LookupContext::create(doc, snapshot, QList<Node*>());
|
||||
const Interpreter::ObjectValue *scopeObject = doc->bind()->findQmlObject(node);
|
||||
|
||||
QStringList prototypes;
|
||||
@@ -211,43 +213,45 @@ void QuickToolBar::apply(TextEditor::BaseTextEditorEditable *editor, Document::P
|
||||
|
||||
}
|
||||
|
||||
bool QuickToolBar::isAvailable(TextEditor::BaseTextEditorEditable *, Document::Ptr doc, const QmlJS::Snapshot &snapshot, AST::Node *node)
|
||||
bool QuickToolBar::isAvailable(TextEditor::BaseTextEditorEditable *, LookupContext::Ptr lookupContext, AST::Node *node)
|
||||
{
|
||||
if (lookupContext.isNull())
|
||||
return false;
|
||||
Document::Ptr doc = lookupContext->document();
|
||||
if (doc.isNull())
|
||||
return false;
|
||||
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
LookupContext::Ptr lookupContext = LookupContext::create(doc, snapshot, QList<Node*>());
|
||||
const Interpreter::ObjectValue *scopeObject = doc->bind()->findQmlObject(node);
|
||||
const Interpreter::ObjectValue *scopeObject = doc->bind()->findQmlObject(node);
|
||||
|
||||
QStringList prototypes;
|
||||
QStringList prototypes;
|
||||
|
||||
while (scopeObject) {
|
||||
prototypes.append(scopeObject->className());
|
||||
scopeObject = scopeObject->prototype(lookupContext->context());
|
||||
while (scopeObject) {
|
||||
prototypes.append(scopeObject->className());
|
||||
scopeObject = scopeObject->prototype(lookupContext->context());
|
||||
}
|
||||
|
||||
if (prototypes.contains("PropertyChanges")) {
|
||||
const Interpreter::ObjectValue *targetObject = getPropertyChangesTarget(node, lookupContext);
|
||||
prototypes.clear();
|
||||
while (targetObject) {
|
||||
prototypes.append(targetObject->className());
|
||||
targetObject = targetObject->prototype(lookupContext->context());
|
||||
}
|
||||
}
|
||||
|
||||
if (prototypes.contains("PropertyChanges")) {
|
||||
const Interpreter::ObjectValue *targetObject = getPropertyChangesTarget(node, lookupContext);
|
||||
prototypes.clear();
|
||||
while (targetObject) {
|
||||
prototypes.append(targetObject->className());
|
||||
targetObject = targetObject->prototype(lookupContext->context());
|
||||
}
|
||||
}
|
||||
|
||||
if (prototypes.contains("Rectangle") ||
|
||||
if (prototypes.contains("Rectangle") ||
|
||||
prototypes.contains("Image") ||
|
||||
prototypes.contains("BorderImage") ||
|
||||
prototypes.contains("TextEdit") ||
|
||||
prototypes.contains("TextInput") ||
|
||||
prototypes.contains("PropertyAnimation") ||
|
||||
prototypes.contains("Text"))
|
||||
return true;
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void QuickToolBar::setProperty(const QString &propertyName, const QVariant &value)
|
||||
|
||||
@@ -30,8 +30,8 @@ class QuickToolBar : public QmlJS::IContextPane
|
||||
public:
|
||||
QuickToolBar(QObject *parent = 0);
|
||||
~QuickToolBar();
|
||||
void apply(TextEditor::BaseTextEditorEditable *editor, QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot, QmlJS::AST::Node *node, bool update, bool force = 0);
|
||||
bool isAvailable(TextEditor::BaseTextEditorEditable *editor, QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot, QmlJS::AST::Node *node);
|
||||
void apply(TextEditor::BaseTextEditorEditable *editor, QmlJS::LookupContext::Ptr lookupContext, QmlJS::AST::Node *node, bool update, bool force = 0);
|
||||
bool isAvailable(TextEditor::BaseTextEditorEditable *editor, QmlJS::LookupContext::Ptr lookupContext, QmlJS::AST::Node *node);
|
||||
void setProperty(const QString &propertyName, const QVariant &value);
|
||||
void removeProperty(const QString &propertyName);
|
||||
void setEnabled(bool);
|
||||
|
||||
Reference in New Issue
Block a user