forked from qt-creator/qt-creator
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -245,6 +245,7 @@ private:
|
||||
|
||||
Internal::SemanticInfoUpdater *m_semanticInfoUpdater;
|
||||
SemanticInfo m_semanticInfo;
|
||||
int m_futureSemanticInfoRevision;
|
||||
|
||||
QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user