Commit 08df2d7d authored by Denis Steckelmacher's avatar Denis Steckelmacher

Every QML/JS file now imports all the other QML/JS files of its directory

This allows QML files to instantiate custom QML components and JS files to use
the functions and variables of other files.

REVIEW: 118743
parent 5a6b8b1b
......@@ -92,6 +92,10 @@ const CompletionParameters QmlCompletionTest::prepareCompletion(const QString& i
Q_ASSERT(topContext);
// Now that it has been parsed, the file can be deleted (this avoids problems
// with files automatically including each other)
fileptr.remove();
// Simulate that the user has entered invokeCode where %INVOKE is, put
// the cursor where %CURRSOR is, and then asked for completions
Q_ASSERT(initCode.indexOf("%INVOKE") != -1);
......
......@@ -34,6 +34,9 @@
#include "parsesession.h"
#include "helper.h"
#include <QtCore/QDirIterator>
#include <QtCore/QFileInfo>
using namespace KDevelop;
DeclarationBuilder::DeclarationBuilder(ParseSession* session)
......@@ -66,6 +69,28 @@ ReferencedTopDUContext DeclarationBuilder::build(const IndexedString& url,
return DeclarationBuilderBase::build(url, node, updateContext);
}
void DeclarationBuilder::startVisiting(QmlJS::AST::Node* node)
{
QFileInfo file(m_session->url().str());
if (file.exists() && !file.absolutePath().contains(QLatin1String("kdevqmljssupport"))) {
// Explore all the files in the same directory as the current file, parse
// them and import their context.
QDirIterator dir(file.absolutePath(), QDir::Files);
DUChainWriteLocker lock;
while (dir.hasNext() && dir.next() != file.absoluteFilePath()) {
ReferencedTopDUContext context = m_session->contextOfFile(dir.filePath());
if (context && context != currentContext()) {
currentContext()->addImportedParentContext(context, CursorInRevision(), true);
}
}
}
DeclarationBuilderBase::startVisiting(node);
}
/*
* Functions
*/
......@@ -618,7 +643,12 @@ void DeclarationBuilder::declareComponentSubclass(QmlJS::AST::UiObjectInitialize
{
DUChainWriteLocker lock;
ClassDeclaration* decl = openDeclaration<ClassDeclaration>(name, RangeInRevision());
ClassDeclaration* decl = openDeclaration<ClassDeclaration>(
currentContext()->type() == DUContext::Global ?
QualifiedIdentifier(m_session->urlBaseName()) :
name,
RangeInRevision()
);
decl->clearBaseClasses();
decl->setAlwaysForceDirect(true); // This declaration has no name, so type->setDeclaration is obliged to store a direct pointer to the declaration.
......
......@@ -41,6 +41,7 @@ public:
virtual KDevelop::ReferencedTopDUContext build(const KDevelop::IndexedString& url,
QmlJS::AST::Node* node,
KDevelop::ReferencedTopDUContext updateContext = KDevelop::ReferencedTopDUContext());
virtual void startVisiting(QmlJS::AST::Node* node);
protected:
using Visitor::visit;
......
......@@ -208,9 +208,21 @@ ReferencedTopDUContext ParseSession::contextOfModule(const QString& module)
return ReferencedTopDUContext();
}
// Get the top context of this module file
ReferencedTopDUContext moduleContext = contextOfFile(moduleFile);
if (moduleContext) {
m_moduleToContext.insert(module, moduleContext);
}
return moduleContext;
}
ReferencedTopDUContext ParseSession::contextOfFile(const QString& fileName)
{
// Get the top context of this module file
DUChainReadLocker lock;
IndexedString moduleFileString(moduleFile);
IndexedString moduleFileString(fileName);
ReferencedTopDUContext moduleContext = DUChain::self()->chainForDocument(moduleFileString);
lock.unlock();
......@@ -232,8 +244,6 @@ ReferencedTopDUContext ParseSession::contextOfModule(const QString& module)
return ReferencedTopDUContext();
} else {
m_moduleToContext.insert(module, moduleContext);
return moduleContext;
}
}
......
......@@ -141,6 +141,16 @@ public:
*/
KDevelop::ReferencedTopDUContext contextOfModule(const QString &module);
/**
* Return the context of a given QML file, NULL if this file is not yet known
* to the DUChain.
*
* When a file that exists is passed to this method and the file hasn't yet
* been parsed, it is queued for parsing, and the current file will also be
* re-parsed after it.
*/
KDevelop::ReferencedTopDUContext contextOfFile(const QString &fileName);
/**
* Dump AST tree to stdout.
*/
......
......@@ -133,7 +133,7 @@ void TestDeclarations::testQMLId()
// First declaration, the anonymous class
ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration *>(top->localDeclarations().first());
QVERIFY(classDecl);
QCOMPARE(classDecl->abstractType()->toString(), QString("<class>"));
QCOMPARE(classDecl->abstractType()->toString(), QString("qmlId"));
QVERIFY(classDecl->internalContext());
QCOMPARE(classDecl->internalContext()->range(), RangeInRevision(5, 6, 5, 37));
......@@ -141,7 +141,7 @@ void TestDeclarations::testQMLId()
Declaration* dec = top->localDeclarations().at(1);
QVERIFY(dec);
QCOMPARE(dec->identifier().toString(), QString("test"));
QCOMPARE(dec->abstractType()->toString(), QString("<class>"));
QCOMPARE(dec->abstractType()->toString(), QString("qmlId"));
oldDec = dec;
}
......@@ -170,7 +170,7 @@ void TestDeclarations::testQMLId()
// First declaration, the anonymous class
ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration *>(top->localDeclarations().first());
QVERIFY(classDecl);
QCOMPARE(classDecl->abstractType()->toString(), QString("<class>"));
QCOMPARE(classDecl->abstractType()->toString(), QString("qmlId"));
QVERIFY(classDecl->internalContext());
QCOMPARE(classDecl->internalContext()->range(), RangeInRevision(5, 6, 6, 17));
......@@ -178,7 +178,7 @@ void TestDeclarations::testQMLId()
Declaration* dec = top->localDeclarations().at(1);
QVERIFY(dec);
QCOMPARE(dec->identifier().toString(), QString("test"));
QCOMPARE(dec->abstractType()->toString(), QString("<class>"));
QCOMPARE(dec->abstractType()->toString(), QString("qmlId"));
}
}
......
......@@ -113,4 +113,8 @@ Module {
return;
}
}
test {
id: i_come_from_test_qml
}
}
import QtQuick 1.1
/**
* "type" : { "toString" : "<class>" }
* "type" : { "toString" : "test" },
* "useCount" : 1
*/
Text {
/*
* "toString" : "<class> someId",
* "toString" : "test someId",
* "useCount" : 3
*/
id: someId
......
......@@ -41,3 +41,5 @@ var nested_conditions = (simple_compare && b < 3);
* "type" : { "toString" : "int" }
*/
var simple_shift = (a << 2);
im_used_in_types_js = "and I'm a string";
......@@ -22,3 +22,8 @@ func(global, i);
*/
var line;
online = false; // onFoo replaced by foo when foo is a QML signal
/**
* "useCount" : 1
*/
var im_used_in_types_js;
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