QmlJS: Fix semantic info update triggering updates.

When a part of the semantic info update (such as a Link) triggers
QmlTextEditorWidget::updateSemanticInfo (for instance by requesting
QML plugin dumps) that update request was ignored because the *old*
semanticInfo revision was compared to the editor revision.

Instead, compare the *future* semantic info revision to check whether
an update would be accepted.

Also, instead of using the same snapshot, get a new one from the model
manager. Otherwise updates to libraryInfos won't be considered.

Change-Id: I0df6197bebce580129292aab5ca8cf24512a0fe7
Reviewed-by: Leandro Melo <leandro.melo@nokia.com>
This commit is contained in:
Christian Kamm
2011-12-02 14:46:23 +01:00
parent 86ba284d06
commit 7b9a42da15
4 changed files with 37 additions and 46 deletions

View File

@@ -658,6 +658,7 @@ QmlJSTextEditorWidget::QmlJSTextEditorWidget(QWidget *parent) :
m_outlineCombo(0),
m_outlineModel(new QmlOutlineModel(this)),
m_modelManager(0),
m_futureSemanticInfoRevision(0),
m_contextPane(0),
m_updateSelectedElements(false),
m_findReferences(new FindReferences(this)),
@@ -891,7 +892,7 @@ void QmlJSTextEditorWidget::onDocumentUpdated(QmlJS::Document::Ptr doc)
if (file()->fileName() != doc->fileName())
return;
if (doc->editorRevision() != document()->revision()) {
if (doc->editorRevision() != editorRevision()) {
// Maybe a dependency changed and our semantic info is now outdated.
// Ignore 0-revision documents though, we get them when a file is initially opened
// in an editor.
@@ -904,7 +905,8 @@ void QmlJSTextEditorWidget::onDocumentUpdated(QmlJS::Document::Ptr doc)
if (doc->ast()) {
// got a correctly parsed (or recovered) file.
m_semanticInfoUpdater->update(SemanticInfoUpdaterSource(doc, m_modelManager->snapshot()));
m_futureSemanticInfoRevision = doc->editorRevision();
m_semanticInfoUpdater->update(doc, m_modelManager->snapshot());
} else {
// show parsing errors
QList<QTextEdit::ExtraSelection> selections;
@@ -1533,9 +1535,9 @@ void QmlJSTextEditorWidget::setTabSettings(const TextEditor::TabSettings &ts)
void QmlJSTextEditorWidget::updateSemanticInfo()
{
// If the document is already out of date, new semantic infos
// If the editor is newer than the future semantic info, new semantic infos
// won't be accepted anyway. What we need is a reparse.
if (isSemanticInfoOutdated())
if (editorRevision() != m_futureSemanticInfoRevision)
return;
// Save time by not doing it for non-active editors.
@@ -1548,20 +1550,19 @@ void QmlJSTextEditorWidget::updateSemanticInfo()
void QmlJSTextEditorWidget::updateSemanticInfoNow()
{
// If the document is already out of date, new semantic infos
// If the editor is newer than the future semantic info, new semantic infos
// won't be accepted anyway. What we need is a reparse.
if (isSemanticInfoOutdated())
if (editorRevision() != m_futureSemanticInfoRevision)
return;
m_updateSemanticInfoTimer->stop();
m_semanticInfoUpdater->update(
SemanticInfoUpdaterSource(m_semanticInfo.document, m_semanticInfo.snapshot));
m_semanticInfoUpdater->reupdate(m_modelManager->snapshot());
}
void QmlJSTextEditorWidget::acceptNewSemanticInfo(const SemanticInfo &semanticInfo)
{
if (semanticInfo.document->editorRevision() != document()->revision()) {
if (semanticInfo.revision() != editorRevision()) {
// ignore outdated semantic infos
return;
}

View File

@@ -245,6 +245,7 @@ private:
Internal::SemanticInfoUpdater *m_semanticInfoUpdater;
SemanticInfo m_semanticInfo;
int m_futureSemanticInfoRevision;
QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;

View File

@@ -59,10 +59,19 @@ void SemanticInfoUpdater::abort()
m_condition.wakeOne();
}
void SemanticInfoUpdater::update(const SemanticInfoUpdaterSource &source)
void SemanticInfoUpdater::update(const QmlJS::Document::Ptr &doc, const QmlJS::Snapshot &snapshot)
{
QMutexLocker locker(&m_mutex);
m_source = source;
m_sourceDocument = doc;
m_sourceSnapshot = snapshot;
m_condition.wakeOne();
}
void SemanticInfoUpdater::reupdate(const QmlJS::Snapshot &snapshot)
{
QMutexLocker locker(&m_mutex);
m_sourceDocument = m_lastSemanticInfo.document;
m_sourceSnapshot = snapshot;
m_condition.wakeOne();
}
@@ -73,22 +82,24 @@ void SemanticInfoUpdater::run()
forever {
m_mutex.lock();
while (! (m_wasCancelled || m_source.isValid()))
while (! (m_wasCancelled || m_sourceDocument))
m_condition.wait(&m_mutex);
const bool done = m_wasCancelled;
const SemanticInfoUpdaterSource source = m_source;
m_source.clear();
QmlJS::Document::Ptr doc = m_sourceDocument;
QmlJS::Snapshot snapshot = m_sourceSnapshot;
m_sourceDocument.clear();
m_sourceSnapshot = QmlJS::Snapshot();
m_mutex.unlock();
if (done)
break;
const SemanticInfo info = makeNewSemanticInfo(source);
const SemanticInfo info = makeNewSemanticInfo(doc, snapshot);
m_mutex.lock();
const bool cancelledOrNewData = m_wasCancelled || m_source.isValid();
const bool cancelledOrNewData = m_wasCancelled || m_sourceDocument;
m_mutex.unlock();
if (! cancelledOrNewData) {
@@ -98,13 +109,13 @@ void SemanticInfoUpdater::run()
}
}
SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const SemanticInfoUpdaterSource &source)
SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const QmlJS::Document::Ptr &doc, const QmlJS::Snapshot &snapshot)
{
using namespace QmlJS;
SemanticInfo semanticInfo;
const Document::Ptr &doc = semanticInfo.document = source.document;
semanticInfo.snapshot = source.snapshot;
semanticInfo.document = doc;
semanticInfo.snapshot = snapshot;
ModelManagerInterface *modelManager = ModelManagerInterface::instance();

View File

@@ -43,30 +43,6 @@
namespace QmlJSEditor {
namespace Internal {
struct SemanticInfoUpdaterSource
{
QmlJS::Document::Ptr document;
QmlJS::Snapshot snapshot;
SemanticInfoUpdaterSource()
{ }
SemanticInfoUpdaterSource(const QmlJS::Document::Ptr &document,
const QmlJS::Snapshot &snapshot)
: document(document)
, snapshot(snapshot)
{ }
bool isValid() const
{ return document; }
void clear()
{
document.clear();
snapshot = QmlJS::Snapshot();
}
};
class SemanticInfoUpdater: public QThread
{
Q_OBJECT
@@ -76,7 +52,8 @@ public:
virtual ~SemanticInfoUpdater();
void abort();
void update(const SemanticInfoUpdaterSource &source);
void update(const QmlJS::Document::Ptr &doc, const QmlJS::Snapshot &snapshot);
void reupdate(const QmlJS::Snapshot &snapshot);
Q_SIGNALS:
void updated(const QmlJSEditor::SemanticInfo &semanticInfo);
@@ -85,13 +62,14 @@ protected:
virtual void run();
private:
SemanticInfo makeNewSemanticInfo(const SemanticInfoUpdaterSource &source);
SemanticInfo makeNewSemanticInfo(const QmlJS::Document::Ptr &doc, const QmlJS::Snapshot &snapshot);
private:
QMutex m_mutex;
QWaitCondition m_condition;
bool m_wasCancelled;
SemanticInfoUpdaterSource m_source;
QmlJS::Document::Ptr m_sourceDocument;
QmlJS::Snapshot m_sourceSnapshot;
SemanticInfo m_lastSemanticInfo;
};