Commit 04ef3766 authored by Kai Koehne's avatar Kai Koehne
Browse files

QmlJS: Move SemanticInfo from qmljseditor to qmljstools



This will allow us to remove the qmljsinspector->qmljseditor
dependency.

Change-Id: I234cf8645edb614e8b1f559a0f9bb6d43e2254c3
Reviewed-by: default avatarFawzi Mohamed <fawzi.mohamed@nokia.com>
parent ae394dfb
......@@ -67,6 +67,7 @@
using namespace QmlJS;
using namespace QmlJSEditor;
using namespace QmlJSTools;
using namespace Internal;
using namespace TextEditor;
......
......@@ -125,14 +125,14 @@ public:
int position,
Core::IDocument *document,
TextEditor::AssistReason reason,
const SemanticInfo &info);
const SemanticInfo &semanticInfo() const;
const QmlJSTools::SemanticInfo &info);
const QmlJSTools::SemanticInfo &semanticInfo() const;
const QIcon &fileNameIcon() const { return m_darkBlueIcon; }
const QIcon &keywordIcon() const { return m_darkYellowIcon; }
const QIcon &symbolIcon() const { return m_darkCyanIcon; }
private:
SemanticInfo m_semanticInfo;
QmlJSTools::SemanticInfo m_semanticInfo;
QIcon m_darkBlueIcon;
QIcon m_darkYellowIcon;
QIcon m_darkCyanIcon;
......
......@@ -45,14 +45,9 @@
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljsevaluate.h>
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljsicontextpane.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/qmljsscopebuilder.h>
#include <qmljs/qmljsutils.h>
#include <qmljs/parser/qmljsastvisitor_p.h>
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/parser/qmljsengine_p.h>
#include <qmljstools/qmljsindenter.h>
#include <qmljstools/qmljsqtstylecodeformatter.h>
......@@ -105,6 +100,7 @@ using namespace QmlJS;
using namespace QmlJS::AST;
using namespace QmlJSEditor;
using namespace QmlJSEditor::Internal;
using namespace QmlJSTools;
namespace {
......@@ -451,208 +447,9 @@ protected:
};
// ### does not necessarily give the full AST path!
// intentionally does not contain lists like
// UiImportList, SourceElements, UiObjectMemberList
class AstPath: protected AST::Visitor
{
QList<AST::Node *> _path;
unsigned _offset;
public:
QList<AST::Node *> operator()(AST::Node *node, unsigned offset)
{
_offset = offset;
_path.clear();
accept(node);
return _path;
}
protected:
using AST::Visitor::visit;
void accept(AST::Node *node)
{
if (node)
node->accept(this);
}
bool containsOffset(AST::SourceLocation start, AST::SourceLocation end)
{
return _offset >= start.begin() && _offset <= end.end();
}
bool handle(AST::Node *ast,
AST::SourceLocation start, AST::SourceLocation end,
bool addToPath = true)
{
if (containsOffset(start, end)) {
if (addToPath)
_path.append(ast);
return true;
}
return false;
}
template <class T>
bool handleLocationAst(T *ast, bool addToPath = true)
{
return handle(ast, ast->firstSourceLocation(), ast->lastSourceLocation(), addToPath);
}
virtual bool preVisit(AST::Node *node)
{
if (Statement *stmt = node->statementCast()) {
return handleLocationAst(stmt);
} else if (ExpressionNode *exp = node->expressionCast()) {
return handleLocationAst(exp);
} else if (UiObjectMember *ui = node->uiObjectMemberCast()) {
return handleLocationAst(ui);
}
return true;
}
virtual bool visit(AST::UiQualifiedId *ast)
{
AST::SourceLocation first = ast->identifierToken;
AST::SourceLocation last;
for (AST::UiQualifiedId *it = ast; it; it = it->next)
last = it->identifierToken;
if (containsOffset(first, last))
_path.append(ast);
return false;
}
virtual bool visit(AST::UiProgram *ast)
{
_path.append(ast);
return true;
}
virtual bool visit(AST::Program *ast)
{
_path.append(ast);
return true;
}
virtual bool visit(AST::UiImport *ast)
{
return handleLocationAst(ast);
}
};
} // end of anonymous namespace
AST::Node *SemanticInfo::rangeAt(int cursorPosition) const
{
AST::Node *declaringMember = 0;
for (int i = ranges.size() - 1; i != -1; --i) {
const Range &range = ranges.at(i);
if (range.begin.isNull() || range.end.isNull()) {
continue;
} else if (cursorPosition >= range.begin.position() && cursorPosition <= range.end.position()) {
declaringMember = range.ast;
break;
}
}
return declaringMember;
}
// ### the name and behavior of this function is dubious
QmlJS::AST::Node *SemanticInfo::declaringMemberNoProperties(int cursorPosition) const
{
AST::Node *node = rangeAt(cursorPosition);
if (UiObjectDefinition *objectDefinition = cast<UiObjectDefinition*>(node)) {
const QString &name = objectDefinition->qualifiedTypeNameId->name.toString();
if (!name.isEmpty() && name.at(0).isLower()) {
QList<AST::Node *> path = rangePath(cursorPosition);
if (path.size() > 1)
return path.at(path.size() - 2);
} else if (name.contains("GradientStop")) {
QList<AST::Node *> path = rangePath(cursorPosition);
if (path.size() > 2)
return path.at(path.size() - 3);
}
} else if (UiObjectBinding *objectBinding = cast<UiObjectBinding*>(node)) {
const QString &name = objectBinding->qualifiedTypeNameId->name.toString();
if (name.contains("Gradient")) {
QList<AST::Node *> path = rangePath(cursorPosition);
if (path.size() > 1)
return path.at(path.size() - 2);
}
}
return node;
}
QList<AST::Node *> SemanticInfo::rangePath(int cursorPosition) const
{
QList<AST::Node *> path;
foreach (const Range &range, ranges) {
if (range.begin.isNull() || range.end.isNull()) {
continue;
} else if (cursorPosition >= range.begin.position() && cursorPosition <= range.end.position()) {
path += range.ast;
}
}
return path;
}
ScopeChain SemanticInfo::scopeChain(const QList<QmlJS::AST::Node *> &path) const
{
Q_ASSERT(m_rootScopeChain);
if (path.isEmpty())
return *m_rootScopeChain;
ScopeChain scope = *m_rootScopeChain;
ScopeBuilder builder(&scope);
builder.push(path);
return scope;
}
QList<AST::Node *> SemanticInfo::astPath(int pos) const
{
QList<AST::Node *> result;
if (! document)
return result;
AstPath astPath;
return astPath(document->ast(), pos);
}
AST::Node *SemanticInfo::astNodeAt(int pos) const
{
const QList<AST::Node *> path = astPath(pos);
if (path.isEmpty())
return 0;
return path.last();
}
bool SemanticInfo::isValid() const
{
if (document && context && m_rootScopeChain)
return true;
return false;
}
int SemanticInfo::revision() const
{
if (document)
return document->editorRevision();
return 0;
}
QmlJSTextEditorWidget::QmlJSTextEditorWidget(QWidget *parent) :
TextEditor::BaseTextEditorWidget(parent),
m_outlineCombo(0),
......@@ -664,7 +461,7 @@ QmlJSTextEditorWidget::QmlJSTextEditorWidget(QWidget *parent) :
m_findReferences(new FindReferences(this)),
m_semanticHighlighter(new SemanticHighlighter(this))
{
qRegisterMetaType<QmlJSEditor::SemanticInfo>("QmlJSEditor::SemanticInfo");
qRegisterMetaType<QmlJSTools::SemanticInfo>("QmlJSTools::SemanticInfo");
m_semanticInfoUpdater = new SemanticInfoUpdater(this);
m_semanticInfoUpdater->start();
......@@ -731,8 +528,8 @@ QmlJSTextEditorWidget::QmlJSTextEditorWidget(QWidget *parent) :
connect(this->document(), SIGNAL(modificationChanged(bool)), this, SLOT(modificationChanged(bool)));
}
connect(m_semanticInfoUpdater, SIGNAL(updated(QmlJSEditor::SemanticInfo)),
this, SLOT(acceptNewSemanticInfo(QmlJSEditor::SemanticInfo)));
connect(m_semanticInfoUpdater, SIGNAL(updated(QmlJSTools::SemanticInfo)),
this, SLOT(acceptNewSemanticInfo(QmlJSTools::SemanticInfo)));
connect(this, SIGNAL(refactorMarkerClicked(TextEditor::RefactorMarker)),
SLOT(onRefactorMarkerClicked(TextEditor::RefactorMarker)));
......
......@@ -35,10 +35,8 @@
#include "qmljseditor_global.h"
#include <qmljs/qmljsdocument.h>
#include <qmljs/qmljsscanner.h>
#include <qmljs/qmljsscopechain.h>
#include <qmljs/qmljsstaticanalysismessage.h>
#include <qmljstools/qmljssemanticinfo.h>
#include <texteditor/basetexteditor.h>
#include <texteditor/quickfix.h>
......@@ -90,61 +88,6 @@ struct QMLJSEDITOR_EXPORT Declaration
{ }
};
class QMLJSEDITOR_EXPORT Range
{
public:
Range(): ast(0) {}
public: // attributes
QmlJS::AST::Node *ast;
QTextCursor begin;
QTextCursor end;
};
class QMLJSEDITOR_EXPORT SemanticInfo
{
public:
SemanticInfo() {}
bool isValid() const;
int revision() const;
// Returns the AST path
QList<QmlJS::AST::Node *> astPath(int cursorPosition) const;
// Returns the AST node at the offset (the last member of the astPath)
QmlJS::AST::Node *astNodeAt(int cursorPosition) const;
// Returns the list of declaration-type nodes that enclose the given position.
// It is more robust than astPath because it tracks ranges with text cursors
// and will thus be correct even if the document was changed and not yet
// reparsed. It does not return the full path of AST nodes.
QList<QmlJS::AST::Node *> rangePath(int cursorPosition) const;
// Returns the declaring member
QmlJS::AST::Node *rangeAt(int cursorPosition) const;
QmlJS::AST::Node *declaringMemberNoProperties(int cursorPosition) const;
// Returns a scopeChain for the given path
QmlJS::ScopeChain scopeChain(const QList<QmlJS::AST::Node *> &path = QList<QmlJS::AST::Node *>()) const;
public: // attributes
QmlJS::Document::Ptr document;
QmlJS::Snapshot snapshot;
QmlJS::ContextPtr context;
QList<Range> ranges;
QHash<QString, QList<QmlJS::AST::SourceLocation> > idLocations;
// these are in addition to the parser messages in the document
QList<QmlJS::DiagnosticMessage> semanticMessages;
QList<QmlJS::StaticAnalysis::Message> staticAnalysisMessages;
private:
QSharedPointer<const QmlJS::ScopeChain> m_rootScopeChain;
friend class Internal::SemanticInfoUpdater;
};
class QMLJSEDITOR_EXPORT QmlJSTextEditorWidget : public TextEditor::BaseTextEditorWidget
{
Q_OBJECT
......@@ -155,7 +98,7 @@ public:
virtual void unCommentSelection();
SemanticInfo semanticInfo() const;
QmlJSTools::SemanticInfo semanticInfo() const;
bool isSemanticInfoOutdated() const;
int editorRevision() const;
......@@ -200,7 +143,7 @@ private slots:
void updateUses();
void updateUsesNow();
void acceptNewSemanticInfo(const QmlJSEditor::SemanticInfo &semanticInfo);
void acceptNewSemanticInfo(const QmlJSTools::SemanticInfo &semanticInfo);
void onCursorPositionChanged();
void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker);
......@@ -243,7 +186,7 @@ private:
QTextCharFormat m_occurrenceRenameFormat;
Internal::SemanticInfoUpdater *m_semanticInfoUpdater;
SemanticInfo m_semanticInfo;
QmlJSTools::SemanticInfo m_semanticInfo;
int m_futureSemanticInfoRevision;
QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;
......
......@@ -118,7 +118,7 @@ void HoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos)
if (matchDiagnosticMessage(qmlEditor, pos))
return;
const QmlJSEditor::SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
const QmlJSTools::SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
if (! semanticInfo.isValid() || qmlEditor->isSemanticInfoOutdated())
return;
......
......@@ -50,13 +50,13 @@ public:
QmlJSQuickFixAssistInterface(QmlJSTextEditorWidget *editor, TextEditor::AssistReason reason);
virtual ~QmlJSQuickFixAssistInterface();
const SemanticInfo &semanticInfo() const;
const QmlJSTools::SemanticInfo &semanticInfo() const;
QmlJSTools::QmlJSRefactoringFilePtr currentFile() const;
QmlJSTextEditorWidget *editor() const;
private:
QmlJSTextEditorWidget *m_editor;
SemanticInfo m_semanticInfo;
QmlJSTools::SemanticInfo m_semanticInfo;
QmlJSTools::QmlJSRefactoringFilePtr m_currentFile;
};
......
......@@ -102,7 +102,7 @@ void SemanticInfoUpdater::run()
if (done)
break;
const SemanticInfo info = makeNewSemanticInfo(doc, snapshot);
const QmlJSTools::SemanticInfo info = makeNewSemanticInfo(doc, snapshot);
m_mutex.lock();
const bool cancelledOrNewData = m_wasCancelled || m_sourceDocument;
......@@ -115,11 +115,11 @@ void SemanticInfoUpdater::run()
}
}
SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const QmlJS::Document::Ptr &doc, const QmlJS::Snapshot &snapshot)
QmlJSTools::SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const QmlJS::Document::Ptr &doc, const QmlJS::Snapshot &snapshot)
{
using namespace QmlJS;
SemanticInfo semanticInfo;
QmlJSTools::SemanticInfo semanticInfo;
semanticInfo.document = doc;
semanticInfo.snapshot = snapshot;
......@@ -129,7 +129,7 @@ SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const QmlJS::Document::Ptr
semanticInfo.context = link(doc, &semanticInfo.semanticMessages);
ScopeChain *scopeChain = new ScopeChain(doc, semanticInfo.context);
semanticInfo.m_rootScopeChain = QSharedPointer<const ScopeChain>(scopeChain);
semanticInfo.setRootScopeChain(QSharedPointer<const ScopeChain>(scopeChain));
if (doc->language() == Document::JsonLanguage) {
Utils::JsonSchema *schema =
......
......@@ -56,13 +56,14 @@ public:
void reupdate(const QmlJS::Snapshot &snapshot);
Q_SIGNALS:
void updated(const QmlJSEditor::SemanticInfo &semanticInfo);
void updated(const QmlJSTools::SemanticInfo &semanticInfo);
protected:
virtual void run();
private:
SemanticInfo makeNewSemanticInfo(const QmlJS::Document::Ptr &doc, const QmlJS::Snapshot &snapshot);
QmlJSTools::SemanticInfo makeNewSemanticInfo(const QmlJS::Document::Ptr &doc,
const QmlJS::Snapshot &snapshot);
private:
QMutex m_mutex;
......@@ -70,7 +71,7 @@ private:
bool m_wasCancelled;
QmlJS::Document::Ptr m_sourceDocument;
QmlJS::Snapshot m_sourceSnapshot;
SemanticInfo m_lastSemanticInfo;
QmlJSTools::SemanticInfo m_lastSemanticInfo;
};
} // namespace Internal
......
......@@ -93,7 +93,7 @@ public:
Qt::ItemFlags flags(const QModelIndex &index) const;
QmlJS::Document::Ptr document() const;
void update(const SemanticInfo &semanticInfo);
void update(const QmlJSTools::SemanticInfo &semanticInfo);
QmlJS::AST::Node *nodeForIndex(const QModelIndex &index) const;
QmlJS::AST::SourceLocation sourceLocation(const QModelIndex &index) const;
......@@ -151,7 +151,7 @@ private:
QHash<QString,QString> getScriptBindings(QmlJS::AST::UiObjectInitializer *objInitializer);
SemanticInfo m_semanticInfo;
QmlJSTools::SemanticInfo m_semanticInfo;
QList<int> m_treePos;
QStandardItem *m_currentItem;
QmlJS::Icons *m_icons;
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "qmljssemanticinfo.h"
#include <qmljs/qmljsscopebuilder.h>
using namespace QmlJS;
using namespace QmlJS::AST;
namespace QmlJSTools {
namespace {
// ### does not necessarily give the full AST path!
// intentionally does not contain lists like
// UiImportList, SourceElements, UiObjectMemberList
class AstPath: protected AST::Visitor
{
QList<AST::Node *> _path;
unsigned _offset;
public:
QList<AST::Node *> operator()(AST::Node *node, unsigned offset)
{
_offset = offset;
_path.clear();
accept(node);
return _path;
}
protected:
using AST::Visitor::visit;
void accept(AST::Node *node)
{
if (node)
node->accept(this);
}
bool containsOffset(AST::SourceLocation start, AST::SourceLocation end)
{
return _offset >= start.begin() && _offset <= end.end();
}
bool handle(AST::Node *ast,
AST::SourceLocation start, AST::SourceLocation end,
bool addToPath = true)
{
if (containsOffset(start, end)) {
if (addToPath)
_path.append(ast);
return true;
}
return false;
}
template <class T>
bool handleLocationAst(T *ast, bool addToPath = true)
{
return handle(ast, ast->firstSourceLocation(), ast->lastSourceLocation(), addToPath);
}
virtual bool preVisit(AST::Node *node)
{
if (Statement *stmt = node->statementCast()) {
return handleLocationAst(stmt);
} else if (ExpressionNode *exp = node->expressionCast()) {
return handleLocationAst(exp);
} else if (UiObjectMember *ui = node->uiObjectMemberCast()) {
return handleLocationAst(ui);
}
return true;
}
virtual bool visit(AST::UiQualifiedId *ast)
{
AST::SourceLocation first = ast->identifierToken;
AST::SourceLocation last;
for (AST::UiQualifiedId *it = ast; it; it = it->next)
last = it->identifierToken;
if (containsOffset(first, last))
_path.append(ast);
return false;
}
virtual bool visit(AST::UiProgram *ast)
{
_path.append(ast);
return true;