Commit 29a61ada authored by Milian Wolff's avatar Milian Wolff

Some work towards a first DUChain'ed QML document.

parent 1551812c
......@@ -17,7 +17,15 @@ add_definitions(-DQML_BUILD_STATIC_LIB=0 -DQMLJS_BUILD_DIR)
add_subdirectory(libs)
add_subdirectory(tests)
kde4_add_plugin(kdevqmljslanguagesupport duchain/contextbuilder.cpp duchain/typebuilder.cpp duchain/declarationbuilder.cpp qmljsparsejob.cpp kdevqmljsplugin.cpp)
kde4_add_plugin(kdevqmljslanguagesupport
duchain/contextbuilder.cpp
duchain/typebuilder.cpp
duchain/declarationbuilder.cpp
duchain/parsesession.cpp
qmljsparsejob.cpp
kdevqmljsplugin.cpp)
target_link_libraries(kdevqmljslanguagesupport kdevqtc-qmlsupport
${QT_QTCORE_LIBRARY} ${KDE4_KDEUI_LIBS} ${KDEVPLATFORM_LANGUAGE_LIBRARIES} ${KDE4_THREADWEAVER_LIBS})
......
/*************************************************************************************
* Copyright (C) 2012 by Aleix Pol <aleixpol@kde.org> *
* Copyright (C) 2012 by Milian Wolff <mail@milianw.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -18,17 +19,47 @@
#include "contextbuilder.h"
KDevelop::DUContext* ContextBuilder::contextFromNode(QmlJS::AST::Node* node)
#include "parsesession.h"
using namespace KDevelop;
ContextBuilder::ContextBuilder()
: ContextBuilderBase()
, m_session(0)
{
}
RangeInRevision ContextBuilder::editorFindRange(QmlJS::AST::Node* fromNode, QmlJS::AST::Node* toNode)
{
return m_session->editorFindRange(fromNode, toNode);
}
QualifiedIdentifier ContextBuilder::identifierForNode(QmlJS::AST::IdentifierPropertyName* node)
{
return 0;
return QualifiedIdentifier(node->id.toString());
}
void ContextBuilder::setContextOnNode(QmlJS::AST::Node* node, KDevelop::DUContext* context)
void ContextBuilder::setContextOnNode(QmlJS::AST::Node* node, DUContext* context)
{
m_astToContext.insert(node, context);
}
DUContext* ContextBuilder::contextFromNode(QmlJS::AST::Node* node)
{
return m_astToContext.value(node, 0);
}
void ContextBuilder::startVisiting(QmlJS::AST::Node* node)
{
QmlJS::AST::Node::accept(node, this);
}
TopDUContext* ContextBuilder::newTopContext(const RangeInRevision& range, ParsingEnvironmentFile* file)
{
if (!file) {
file = new ParsingEnvironmentFile(m_session->url());
/// Indexed string for 'Php', identifies environment files from this language plugin
file->setLanguage(m_session->languageString());
}
return ContextBuilderBase::newTopContext(range, file);
}
/*************************************************************************************
* Copyright (C) 2012 by Aleix Pol <aleixpol@kde.org> *
* Copyright (C) 2012 by Milian Wolff <mail@milianw.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -21,14 +22,29 @@
#include <language/duchain/builders/abstractcontextbuilder.h>
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsdocument.h>
class ContextBuilder : public KDevelop::AbstractContextBuilder<QmlJS::AST::Node, QmlJS::AST::IdentifierPropertyName>
, public QmlJS::AST::Visitor
class ParseSession;
typedef KDevelop::AbstractContextBuilder<QmlJS::AST::Node, QmlJS::AST::IdentifierPropertyName> ContextBuilderBase;
class ContextBuilder : public ContextBuilderBase, public QmlJS::AST::Visitor
{
public:
virtual KDevelop::DUContext* contextFromNode(QmlJS::AST::Node* node);
virtual void setContextOnNode(QmlJS::AST::Node* node, KDevelop::DUContext* context);
virtual void startVisiting(QmlJS::AST::Node* node);
public:
ContextBuilder();
virtual void startVisiting(QmlJS::AST::Node* node);
virtual KDevelop::RangeInRevision editorFindRange(QmlJS::AST::Node* fromNode, QmlJS::AST::Node* toNode);
virtual KDevelop::QualifiedIdentifier identifierForNode(QmlJS::AST::IdentifierPropertyName* node);
virtual void setContextOnNode(QmlJS::AST::Node* node, KDevelop::DUContext* context);
virtual KDevelop::DUContext* contextFromNode(QmlJS::AST::Node* node);
virtual KDevelop::TopDUContext* newTopContext(const KDevelop::RangeInRevision& range,
KDevelop::ParsingEnvironmentFile* file = 0);
protected:
ParseSession* m_session;
QHash<QmlJS::AST::Node*, KDevelop::DUContext*> m_astToContext;
};
#endif // CONTEXTBUILDER_H
/*************************************************************************************
* Copyright (C) 2012 by Aleix Pol <aleixpol@kde.org> *
* Copyright (C) 2012 by Milian Wolff <mail@milianw.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -17,21 +18,19 @@
*************************************************************************************/
#include "declarationbuilder.h"
#include "parsesession.h"
KDevelop::SimpleRange locationToSimpleRange(QmlJS::AST::SourceLocation location);
DeclarationBuilder::DeclarationBuilder(QmlJS::Document::MutablePtr ptr)
: m_doc(ptr)
{}
KDevelop::RangeInRevision DeclarationBuilder::editorFindRange(QmlJS::AST::Node* fromNode, QmlJS::AST::Node* toNode)
DeclarationBuilder::DeclarationBuilder(ParseSession* session)
{
return KDevelop::RangeInRevision::castFromSimpleRange(KDevelop::SimpleRange(
locationToSimpleRange(fromNode->lastSourceLocation()).end,
locationToSimpleRange(toNode->firstSourceLocation()).start));
m_session = session;
}
KDevelop::QualifiedIdentifier DeclarationBuilder::identifierForNode(QmlJS::AST::IdentifierPropertyName* node)
KDevelop::ReferencedTopDUContext DeclarationBuilder::build(const KDevelop::IndexedString& url,
QmlJS::AST::Node* node,
KDevelop::ReferencedTopDUContext updateContext)
{
return KDevelop::QualifiedIdentifier(node->id.toString());
///TODO: cleanup
Q_ASSERT(m_session->url() == url);
return DeclarationBuilderBase::build(url, node, updateContext);
}
/*************************************************************************************
* Copyright (C) 2012 by Aleix Pol <aleixpol@kde.org> *
* Copyright (C) 2012 by Milian Wolff <mail@milianw.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -20,20 +21,19 @@
#define DECLARATIONBUILDER_H
#include <language/duchain/builders/abstractdeclarationbuilder.h>
#include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsdocument.h>
#include "typebuilder.h"
class DeclarationBuilder : public KDevelop::AbstractDeclarationBuilder<QmlJS::AST::Node, QmlJS::AST::IdentifierPropertyName, TypeBuilder>
typedef KDevelop::AbstractDeclarationBuilder<QmlJS::AST::Node, QmlJS::AST::IdentifierPropertyName, TypeBuilder> DeclarationBuilderBase;
class DeclarationBuilder : public DeclarationBuilderBase
{
public:
DeclarationBuilder(QmlJS::Document::MutablePtr ptr);
virtual KDevelop::QualifiedIdentifier identifierForNode(QmlJS::AST::IdentifierPropertyName* node);
virtual KDevelop::RangeInRevision editorFindRange(QmlJS::AST::Node* fromNode, QmlJS::AST::Node* toNode);
public:
DeclarationBuilder(ParseSession* session);
private:
QmlJS::Document::MutablePtr m_doc;
virtual KDevelop::ReferencedTopDUContext build(const KDevelop::IndexedString& url,
QmlJS::AST::Node* node,
KDevelop::ReferencedTopDUContext updateContext = KDevelop::ReferencedTopDUContext());
};
#endif // DECLARATIONBUILDER_H
/*************************************************************************************
* Copyright (C) 2012 by Milian Wolff <mail@milianw.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
*************************************************************************************/
#include "parsesession.h"
#include <qmljs/parser/qmljsast_p.h>
#include <language/editor/simplerange.h>
#include <language/interfaces/iproblem.h>
using namespace KDevelop;
SimpleRange ParseSession::locationToSimpleRange(QmlJS::AST::SourceLocation location)
{
return SimpleRange(location.startLine, location.startColumn, location.startLine, location.length);
}
RangeInRevision ParseSession::editorFindRange(QmlJS::AST::Node* fromNode, QmlJS::AST::Node* toNode)
{
return RangeInRevision::castFromSimpleRange(SimpleRange(
locationToSimpleRange(fromNode->firstSourceLocation()).start,
locationToSimpleRange(toNode->lastSourceLocation()).end
));
}
IndexedString ParseSession::languageString()
{
static const IndexedString langString("QML/JS");
return langString;
}
ParseSession::ParseSession(const IndexedString& url, const QString& contents)
: m_url(url)
{
const QString path = m_url.str();
m_doc = QmlJS::Document::create(path, QmlJS::Document::guessLanguageFromSuffix(path));
m_doc->setSource(contents);
m_doc->parse();
}
QmlJS::AST::Node* ParseSession::ast() const
{
return m_doc->ast();
}
IndexedString ParseSession::url() const
{
return m_url;
}
QVector<ProblemPointer> ParseSession::problems() const
{
QVector<ProblemPointer> problems;
foreach(const QmlJS::DiagnosticMessage& msg, m_doc->diagnosticMessages()) {
ProblemPointer p(new Problem);
p->setDescription(msg.message);
p->setFinalLocation(DocumentRange(m_url, locationToSimpleRange(msg.loc)));
}
return problems;
}
/*************************************************************************************
* Copyright (C) 2012 by Milian Wolff <mail@milianw.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
*************************************************************************************/
#ifndef PARSESESSION_H
#define PARSESESSION_H
#include <qmljs/qmljsdocument.h>
#include <language/duchain/indexedstring.h>
#include <language/duchain/topducontext.h>
namespace KDevelop
{
class SimpleRange;
}
/**
* This class wraps the qmljs parser and offers some helper functions
* that make it simpler to use the parser in KDevelop.
*/
class ParseSession
{
public:
/**
* Convert @p location to a KDevelop::SimpleRange and return that.
*/
static KDevelop::SimpleRange locationToSimpleRange(QmlJS::AST::SourceLocation location);
/**
* @return a range that spans @p fromNode and @p toNode.
*/
static KDevelop::RangeInRevision editorFindRange(QmlJS::AST::Node* fromNode,
QmlJS::AST::Node* toNode);
/**
* @return a unique identifier for QML/JS documents.
*/
static KDevelop::IndexedString languageString();
/**
* Parse the given @p contents.
*
* @param url The url for the document you want to parse.
* @param contents The contents of the document you want to parse.
*/
ParseSession(const KDevelop::IndexedString& url, const QString& contents);
/**
* @return the URL of this session
*/
KDevelop::IndexedString url() const;
/**
* @return the root AST node or null if it failed to parse.
*/
QmlJS::AST::Node* ast() const;
/**
* @return the problems encountered during parsing.
*/
QVector<KDevelop::ProblemPointer> problems() const;
private:
KDevelop::IndexedString m_url;
QmlJS::Document::MutablePtr m_doc;
};
#endif // PARSESESSION_H
/*************************************************************************************
* Copyright (C) 2012 by Aleix Pol <aleixpol@kde.org> *
* Copyright (C) 2012 by Milian Wolff <mail@milianw.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -18,3 +19,10 @@
#include "typebuilder.h"
using namespace KDevelop;
TypeBuilder::TypeBuilder()
: TypeBuilderBase()
{
}
/*************************************************************************************
* Copyright (C) 2012 by Aleix Pol <aleixpol@kde.org> *
* Copyright (C) 2012 by Milian Wolff <mail@milianw.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
......@@ -20,11 +21,15 @@
#define TYPEBUILDER_H
#include <language/duchain/builders/abstracttypebuilder.h>
#include <qmljs/parser/qmljsast_p.h>
#include "contextbuilder.h"
class TypeBuilder : public KDevelop::AbstractTypeBuilder<QmlJS::AST::Node, QmlJS::AST::IdentifierPropertyName, ContextBuilder>
typedef KDevelop::AbstractTypeBuilder<QmlJS::AST::Node, QmlJS::AST::IdentifierPropertyName, ContextBuilder> TypeBuilderBase;
class TypeBuilder : public TypeBuilderBase
{
public:
TypeBuilder();
};
#endif // TYPEBUILDER_H
......@@ -28,9 +28,9 @@
#include <interfaces/ilanguage.h>
#include <interfaces/icore.h>
#include <interfaces/ilanguagecontroller.h>
#include <qmljs/qmljsdocument.h>
#include "kdevqmljsplugin.h"
#include "duchain/declarationbuilder.h"
#include "duchain/parsesession.h"
#include <QReadLocker>
......@@ -40,16 +40,10 @@ QmlJsParseJob::QmlJsParseJob(const IndexedString& url, ILanguageSupport* languag
: ParseJob(url, languageSupport)
{}
SimpleRange locationToSimpleRange(QmlJS::AST::SourceLocation location)
{
return SimpleRange(location.startLine, location.startColumn, location.startLine, location.length);
}
void QmlJsParseJob::run()
{
UrlParseLock urlLock(document());
static const IndexedString langString("qml/js");
if (abortRequested() || !isUpdateRequired(langString)) {
if (abortRequested() || !isUpdateRequired(ParseSession::languageString())) {
return;
}
......@@ -61,11 +55,9 @@ void QmlJsParseJob::run()
return abortJob();
}
const QString url = document().str();
QmlJS::Document::MutablePtr doc = QmlJS::Document::create(url, QmlJS::Document::guessLanguageFromSuffix(url));
doc->setSource(contents().contents);
ParseSession session(document(), contents().contents);
// 2) parse
const bool successfullyParsed = doc->parse();
const bool successfullyParsed = session.ast();
if (abortRequested() || ICore::self()->shuttingDown()) {
return abortJob();
......@@ -84,8 +76,8 @@ void QmlJsParseJob::run()
QReadLocker parseLock(languageSupport()->language()->parseLock());
DeclarationBuilder builder(doc);
ReferencedTopDUContext chain = builder.build(document(), doc->ast(), toUpdate);
DeclarationBuilder builder(&session);
ReferencedTopDUContext chain = builder.build(document(), session.ast(), toUpdate);
if (abortRequested()) {
return abortJob();
......@@ -100,11 +92,8 @@ void QmlJsParseJob::run()
{
DUChainWriteLocker lock(DUChain::lock());
foreach(const QmlJS::DiagnosticMessage& msg, doc->diagnosticMessages()) {
ProblemPointer p(new Problem);
p->setDescription(msg.message);
p->setFinalLocation(DocumentRange(IndexedString(doc->fileName()), locationToSimpleRange(msg.loc)));
chain->addProblem(p);
foreach(const ProblemPointer& problem, session.problems()) {
chain->addProblem(problem);
}
chain->setFeatures(minimumFeatures());
......@@ -133,10 +122,7 @@ void QmlJsParseJob::run()
top = new TopDUContext(document(), RangeInRevision(0, 0, INT_MAX, INT_MAX), file);
DUChain::self()->addDocumentChain(top);
}
foreach(const QmlJS::DiagnosticMessage& msg, doc->diagnosticMessages()) {
ProblemPointer p(new Problem);
p->setDescription(msg.message);
p->setFinalLocation(DocumentRange(IndexedString(doc->fileName()), locationToSimpleRange(msg.loc)));
foreach(const ProblemPointer& p, session.problems()) {
top->addProblem(p);
}
setDuChain(top);
......
......@@ -36,6 +36,10 @@ public:
void parseFile( const QString &fileName )
{
m_document = QmlJS::Document::create(fileName, QmlJS::Document::guessLanguageFromSuffix(fileName));
QFile file(fileName);
file.open(QIODevice::ReadOnly);
m_document->setSource(file.readAll());
runSession();
}
/// parse code directly
......@@ -72,7 +76,7 @@ private:
if (!m_document->diagnosticMessages().isEmpty()) {
qerr << endl << "problems encountered during parsing:" << endl;
foreach(const QmlJS::DiagnosticMessage& msg, m_document->diagnosticMessages()) {
qerr << msg.message << msg.loc.startLine << msg.loc.startColumn << msg.loc.length << msg.loc.offset << msg.kind;
qerr << msg.message << " in [" << msg.loc.startLine << ", " << msg.loc.startColumn << "] (length:" << msg.loc.length << ", offset: " << msg.loc.offset << ", kind: " << msg.kind << ")" << endl;
}
} else {
qout << "no problems encountered during parsing" << endl;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment