forked from qt-creator/qt-creator
qml debugger: Use a hash table to store the debugId
This should speed up the matching between the AST nodes and the debugIds
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
#include "qmljsclientproxy.h"
|
#include "qmljsclientproxy.h"
|
||||||
#include "qmljsprivateapi.h"
|
#include "qmljsprivateapi.h"
|
||||||
#include "qmljsdesigndebugclient.h"
|
#include "qmljsdesigndebugclient.h"
|
||||||
|
#include "qmljsinspector.h"
|
||||||
|
|
||||||
#include <debugger/debuggerplugin.h>
|
#include <debugger/debuggerplugin.h>
|
||||||
#include <debugger/debuggerrunner.h>
|
#include <debugger/debuggerrunner.h>
|
||||||
@@ -37,10 +38,12 @@
|
|||||||
#include <debugger/qml/qmladapter.h>
|
#include <debugger/qml/qmladapter.h>
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <projectexplorer/project.h>
|
||||||
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QAbstractSocket>
|
#include <QAbstractSocket>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
using namespace QmlJSInspector::Internal;
|
using namespace QmlJSInspector::Internal;
|
||||||
|
|
||||||
@@ -328,6 +331,11 @@ void ClientProxy::objectTreeFetched(QDeclarativeDebugQuery::State state)
|
|||||||
delete query;
|
delete query;
|
||||||
|
|
||||||
if (m_objectTreeQuery.isEmpty()) {
|
if (m_objectTreeQuery.isEmpty()) {
|
||||||
|
int old_count = m_debugIdHash.count();
|
||||||
|
m_debugIdHash.clear();
|
||||||
|
m_debugIdHash.reserve(old_count + 1);
|
||||||
|
foreach(const QDeclarativeDebugObjectReference &it, m_rootObjects)
|
||||||
|
buildDebugIdHashRecursive(it);
|
||||||
emit objectTreeUpdated();
|
emit objectTreeUpdated();
|
||||||
|
|
||||||
if (isDesignClientConnected()) {
|
if (isDesignClientConnected()) {
|
||||||
@@ -339,6 +347,38 @@ void ClientProxy::objectTreeFetched(QDeclarativeDebugQuery::State state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientProxy::buildDebugIdHashRecursive(const QDeclarativeDebugObjectReference& ref)
|
||||||
|
{
|
||||||
|
QString filename = ref.source().url().toLocalFile();
|
||||||
|
int lineNum = ref.source().lineNumber();
|
||||||
|
int colNum = ref.source().columnNumber();
|
||||||
|
int rev = 0;
|
||||||
|
static QRegExp rx("^(.*)_(\\d+):(\\d+)$");
|
||||||
|
if (rx.exactMatch(filename)) {
|
||||||
|
filename = rx.cap(1);
|
||||||
|
rev = rx.cap(2).toInt();
|
||||||
|
lineNum += rx.cap(3).toInt() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//convert the filename to a canonical filename in case of febug build.
|
||||||
|
bool isShadowBuild = InspectorUi::instance()->isShadowBuildProject();
|
||||||
|
if (isShadowBuild && rev == 0) {
|
||||||
|
QString shadowBuildDir = InspectorUi::instance()->debugProjectBuildDirectory();
|
||||||
|
|
||||||
|
//QFileInfo objectFileInfo(filename);
|
||||||
|
if (filename.startsWith(shadowBuildDir)) {
|
||||||
|
ProjectExplorer::Project *debugProject = InspectorUi::instance()->debugProject();
|
||||||
|
filename = debugProject->projectDirectory() + filename.mid(shadowBuildDir.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_debugIdHash[qMakePair<QString, int>(filename, rev)][qMakePair<int, int>(lineNum, colNum)].append(ref.debugId());
|
||||||
|
|
||||||
|
foreach(const QDeclarativeDebugObjectReference &it, ref.children())
|
||||||
|
buildDebugIdHashRecursive(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ClientProxy::reloadQmlViewer()
|
void ClientProxy::reloadQmlViewer()
|
||||||
{
|
{
|
||||||
if (isDesignClientConnected())
|
if (isDesignClientConnected())
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ class QmlAdapter;
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace QmlJSInspector {
|
namespace QmlJSInspector {
|
||||||
|
|
||||||
|
//map <filename, editorRevision> -> <lineNumber, columnNumber> -> debugIds
|
||||||
|
typedef QHash<QPair<QString, int>, QHash<QPair<int, int>, QList<int> > > DebugIdHash;
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class InspectorPlugin;
|
class InspectorPlugin;
|
||||||
@@ -67,6 +71,7 @@ public:
|
|||||||
QList<QDeclarativeDebugObjectReference> objectReferences(const QUrl &url = QUrl()) const;
|
QList<QDeclarativeDebugObjectReference> objectReferences(const QUrl &url = QUrl()) const;
|
||||||
QDeclarativeDebugObjectReference objectReferenceForId(int debugId) const;
|
QDeclarativeDebugObjectReference objectReferenceForId(int debugId) const;
|
||||||
QList<QDeclarativeDebugObjectReference> rootObjectReference() const;
|
QList<QDeclarativeDebugObjectReference> rootObjectReference() const;
|
||||||
|
DebugIdHash debugIdHash() const { return m_debugIdHash; };
|
||||||
|
|
||||||
bool isConnected() const;
|
bool isConnected() const;
|
||||||
|
|
||||||
@@ -137,6 +142,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Q_DISABLE_COPY(ClientProxy);
|
Q_DISABLE_COPY(ClientProxy);
|
||||||
|
void buildDebugIdHashRecursive(const QDeclarativeDebugObjectReference &ref);
|
||||||
|
|
||||||
Debugger::Internal::QmlAdapter *m_adapter;
|
Debugger::Internal::QmlAdapter *m_adapter;
|
||||||
QDeclarativeEngineDebug *m_client;
|
QDeclarativeEngineDebug *m_client;
|
||||||
@@ -149,6 +155,7 @@ private:
|
|||||||
QList<QDeclarativeDebugObjectReference> m_rootObjects;
|
QList<QDeclarativeDebugObjectReference> m_rootObjects;
|
||||||
QList<QDeclarativeDebugEngineReference> m_engines;
|
QList<QDeclarativeDebugEngineReference> m_engines;
|
||||||
QTimer m_requestObjectsTimer;
|
QTimer m_requestObjectsTimer;
|
||||||
|
DebugIdHash m_debugIdHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -71,16 +71,15 @@ class MapObjectWithDebugReference : public Visitor
|
|||||||
virtual bool visit(UiObjectDefinition *ast) ;
|
virtual bool visit(UiObjectDefinition *ast) ;
|
||||||
virtual bool visit(UiObjectBinding *ast) ;
|
virtual bool visit(UiObjectBinding *ast) ;
|
||||||
|
|
||||||
QList<QDeclarativeDebugObjectReference> root;
|
QHash<QPair<int, int>, DebugIdList> ids;
|
||||||
QString filename;
|
QString filename;
|
||||||
QHash<UiObjectMember *, DebugIdList> result;
|
QHash<UiObjectMember *, DebugIdList> result;
|
||||||
QSet<QmlJS::AST::UiObjectMember *> lookupObjects;
|
QSet<UiObjectMember *> lookupObjects;
|
||||||
Document::Ptr doc;
|
|
||||||
private:
|
private:
|
||||||
bool filenamesMatch(const QString &objectFileName, const QString &buildFilename) const;
|
void process(UiObjectMember *ast);
|
||||||
private:
|
private:
|
||||||
int activated;
|
int activated;
|
||||||
void processRecursive(const QDeclarativeDebugObjectReference &object, UiObjectMember *ast);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool MapObjectWithDebugReference::visit(UiObjectDefinition* ast)
|
bool MapObjectWithDebugReference::visit(UiObjectDefinition* ast)
|
||||||
@@ -99,66 +98,25 @@ bool MapObjectWithDebugReference::visit(UiObjectBinding* ast)
|
|||||||
|
|
||||||
void MapObjectWithDebugReference::endVisit(UiObjectDefinition* ast)
|
void MapObjectWithDebugReference::endVisit(UiObjectDefinition* ast)
|
||||||
{
|
{
|
||||||
if (lookupObjects.isEmpty() || activated) {
|
process(ast);
|
||||||
foreach(const QDeclarativeDebugObjectReference& it, root)
|
|
||||||
processRecursive(it, ast);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lookupObjects.contains(ast))
|
if (lookupObjects.contains(ast))
|
||||||
activated--;
|
activated--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapObjectWithDebugReference::endVisit(UiObjectBinding* ast)
|
void MapObjectWithDebugReference::endVisit(UiObjectBinding* ast)
|
||||||
{
|
{
|
||||||
if (lookupObjects.isEmpty() || activated) {
|
process(ast);
|
||||||
foreach(const QDeclarativeDebugObjectReference& it, root)
|
|
||||||
processRecursive(it, ast);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lookupObjects.contains(ast))
|
if (lookupObjects.contains(ast))
|
||||||
activated--;
|
activated--;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MapObjectWithDebugReference::filenamesMatch(const QString &objectFileName, const QString &buildFilename) const
|
void MapObjectWithDebugReference::process(UiObjectMember* ast)
|
||||||
{
|
{
|
||||||
bool isShadowBuild = InspectorUi::instance()->isShadowBuildProject();
|
if (lookupObjects.isEmpty() || activated) {
|
||||||
ProjectExplorer::Project *debugProject = InspectorUi::instance()->debugProject();
|
SourceLocation loc = ast->firstSourceLocation();
|
||||||
|
QHash<QPair<int, int>, DebugIdList>::const_iterator it = ids.constFind(qMakePair<int, int>(loc.startLine, loc.startColumn));
|
||||||
if (!isShadowBuild) {
|
if (it != ids.constEnd())
|
||||||
return (objectFileName == buildFilename);
|
result[ast].append(*it);
|
||||||
} else {
|
|
||||||
QString projectDir = debugProject->projectDirectory();
|
|
||||||
QString shadowBuildDir = InspectorUi::instance()->debugProjectBuildDirectory();
|
|
||||||
|
|
||||||
QFileInfo objectFileInfo(objectFileName);
|
|
||||||
QFileInfo buildFileInfo(buildFilename);
|
|
||||||
QString objectRelativePath = objectFileInfo.absoluteFilePath().mid(shadowBuildDir.length());
|
|
||||||
QString buildRelativePath = buildFileInfo.absoluteFilePath().mid(projectDir.length());
|
|
||||||
|
|
||||||
return (objectRelativePath == buildRelativePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObjectReference& object, UiObjectMember* ast)
|
|
||||||
{
|
|
||||||
// If this is too slow, it can be speed up by indexing
|
|
||||||
// the QDeclarativeDebugObjectReference by filename/loc in a fist pass
|
|
||||||
|
|
||||||
SourceLocation loc = ast->firstSourceLocation();
|
|
||||||
if (object.source().columnNumber() == int(loc.startColumn)) {
|
|
||||||
QString objectFileName = object.source().url().toLocalFile();
|
|
||||||
if (!doc && object.source().lineNumber() == int(loc.startLine) && filenamesMatch(objectFileName, filename)) {
|
|
||||||
result[ast] += object.debugId();
|
|
||||||
} else if (doc && objectFileName.startsWith(filename + QLatin1Char('_') + QString::number(doc->editorRevision()) + QLatin1Char(':'))) {
|
|
||||||
bool ok;
|
|
||||||
int line = objectFileName.mid(objectFileName.lastIndexOf(':') + 1).toInt(&ok);
|
|
||||||
if (ok && int(loc.startLine) == line + object.source().lineNumber() - 1)
|
|
||||||
result[ast] += object.debugId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (const QDeclarativeDebugObjectReference &it, object.children()) {
|
|
||||||
processRecursive(it, ast);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,10 +272,13 @@ void QmlJSLiveTextPreview::updateDebugIds()
|
|||||||
if (!clientProxy)
|
if (!clientProxy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
{ // Map all the object that comes from the document as it has been loaded by the server.
|
DebugIdHash::const_iterator it = clientProxy->debugIdHash().constFind(qMakePair<QString, int>(m_initialDoc->fileName(), 0));
|
||||||
|
if (it != clientProxy->debugIdHash().constEnd()) {
|
||||||
|
// Map all the object that comes from the document as it has been loaded by the server.
|
||||||
const QmlJS::Document::Ptr &doc = m_initialDoc;
|
const QmlJS::Document::Ptr &doc = m_initialDoc;
|
||||||
|
|
||||||
MapObjectWithDebugReference visitor;
|
MapObjectWithDebugReference visitor;
|
||||||
visitor.root = clientProxy->rootObjectReference();
|
visitor.ids = (*it);
|
||||||
visitor.filename = doc->fileName();
|
visitor.filename = doc->fileName();
|
||||||
doc->qmlProgram()->accept(&visitor);
|
doc->qmlProgram()->accept(&visitor);
|
||||||
|
|
||||||
@@ -347,11 +308,16 @@ void QmlJSLiveTextPreview::updateDebugIds()
|
|||||||
it != m_createdObjects.constEnd(); ++it) {
|
it != m_createdObjects.constEnd(); ++it) {
|
||||||
|
|
||||||
const QmlJS::Document::Ptr &doc = it.key();
|
const QmlJS::Document::Ptr &doc = it.key();
|
||||||
|
|
||||||
|
DebugIdHash::const_iterator id_it = clientProxy->debugIdHash().constFind(
|
||||||
|
qMakePair<QString, int>(doc->fileName(), doc->editorRevision()));
|
||||||
|
if (id_it == clientProxy->debugIdHash().constEnd())
|
||||||
|
continue;
|
||||||
|
|
||||||
MapObjectWithDebugReference visitor;
|
MapObjectWithDebugReference visitor;
|
||||||
visitor.root = clientProxy->rootObjectReference();
|
visitor.ids = *id_it;
|
||||||
visitor.filename = doc->fileName();
|
visitor.filename = doc->fileName();
|
||||||
visitor.lookupObjects = it.value();
|
visitor.lookupObjects = it.value();
|
||||||
visitor.doc = doc;
|
|
||||||
doc->qmlProgram()->accept(&visitor);
|
doc->qmlProgram()->accept(&visitor);
|
||||||
|
|
||||||
Delta::DebugIdMap debugIds = visitor.result;
|
Delta::DebugIdMap debugIds = visitor.result;
|
||||||
|
|||||||
Reference in New Issue
Block a user