forked from qt-creator/qt-creator
QmlJS: Move SemanticInfo from qmljseditor to qmljstools
This will allow us to remove the qmljsinspector->qmljseditor dependency. Change-Id: I234cf8645edb614e8b1f559a0f9bb6d43e2254c3 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user