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 ...@@ -92,6 +92,10 @@ const CompletionParameters QmlCompletionTest::prepareCompletion(const QString& i
Q_ASSERT(topContext); 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 // Simulate that the user has entered invokeCode where %INVOKE is, put
// the cursor where %CURRSOR is, and then asked for completions // the cursor where %CURRSOR is, and then asked for completions
Q_ASSERT(initCode.indexOf("%INVOKE") != -1); Q_ASSERT(initCode.indexOf("%INVOKE") != -1);
......
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
#include "parsesession.h" #include "parsesession.h"
#include "helper.h" #include "helper.h"
#include <QtCore/QDirIterator>
#include <QtCore/QFileInfo>
using namespace KDevelop; using namespace KDevelop;
DeclarationBuilder::DeclarationBuilder(ParseSession* session) DeclarationBuilder::DeclarationBuilder(ParseSession* session)
...@@ -66,6 +69,28 @@ ReferencedTopDUContext DeclarationBuilder::build(const IndexedString& url, ...@@ -66,6 +69,28 @@ ReferencedTopDUContext DeclarationBuilder::build(const IndexedString& url,
return DeclarationBuilderBase::build(url, node, updateContext); 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 * Functions
*/ */
...@@ -618,7 +643,12 @@ void DeclarationBuilder::declareComponentSubclass(QmlJS::AST::UiObjectInitialize ...@@ -618,7 +643,12 @@ void DeclarationBuilder::declareComponentSubclass(QmlJS::AST::UiObjectInitialize
{ {
DUChainWriteLocker lock; 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->clearBaseClasses();
decl->setAlwaysForceDirect(true); // This declaration has no name, so type->setDeclaration is obliged to store a direct pointer to the declaration. 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: ...@@ -41,6 +41,7 @@ public:
virtual KDevelop::ReferencedTopDUContext build(const KDevelop::IndexedString& url, virtual KDevelop::ReferencedTopDUContext build(const KDevelop::IndexedString& url,
QmlJS::AST::Node* node, QmlJS::AST::Node* node,
KDevelop::ReferencedTopDUContext updateContext = KDevelop::ReferencedTopDUContext()); KDevelop::ReferencedTopDUContext updateContext = KDevelop::ReferencedTopDUContext());
virtual void startVisiting(QmlJS::AST::Node* node);
protected: protected:
using Visitor::visit; using Visitor::visit;
......
...@@ -208,9 +208,21 @@ ReferencedTopDUContext ParseSession::contextOfModule(const QString& module) ...@@ -208,9 +208,21 @@ ReferencedTopDUContext ParseSession::contextOfModule(const QString& module)
return ReferencedTopDUContext(); 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 // Get the top context of this module file
DUChainReadLocker lock; DUChainReadLocker lock;
IndexedString moduleFileString(moduleFile); IndexedString moduleFileString(fileName);
ReferencedTopDUContext moduleContext = DUChain::self()->chainForDocument(moduleFileString); ReferencedTopDUContext moduleContext = DUChain::self()->chainForDocument(moduleFileString);
lock.unlock(); lock.unlock();
...@@ -232,8 +244,6 @@ ReferencedTopDUContext ParseSession::contextOfModule(const QString& module) ...@@ -232,8 +244,6 @@ ReferencedTopDUContext ParseSession::contextOfModule(const QString& module)
return ReferencedTopDUContext(); return ReferencedTopDUContext();
} else { } else {
m_moduleToContext.insert(module, moduleContext);
return moduleContext; return moduleContext;
} }
} }
......
...@@ -141,6 +141,16 @@ public: ...@@ -141,6 +141,16 @@ public:
*/ */
KDevelop::ReferencedTopDUContext contextOfModule(const QString &module); 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. * Dump AST tree to stdout.
*/ */
......
...@@ -133,7 +133,7 @@ void TestDeclarations::testQMLId() ...@@ -133,7 +133,7 @@ void TestDeclarations::testQMLId()
// First declaration, the anonymous class // First declaration, the anonymous class
ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration *>(top->localDeclarations().first()); ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration *>(top->localDeclarations().first());
QVERIFY(classDecl); QVERIFY(classDecl);
QCOMPARE(classDecl->abstractType()->toString(), QString("<class>")); QCOMPARE(classDecl->abstractType()->toString(), QString("qmlId"));
QVERIFY(classDecl->internalContext()); QVERIFY(classDecl->internalContext());
QCOMPARE(classDecl->internalContext()->range(), RangeInRevision(5, 6, 5, 37)); QCOMPARE(classDecl->internalContext()->range(), RangeInRevision(5, 6, 5, 37));
...@@ -141,7 +141,7 @@ void TestDeclarations::testQMLId() ...@@ -141,7 +141,7 @@ void TestDeclarations::testQMLId()
Declaration* dec = top->localDeclarations().at(1); Declaration* dec = top->localDeclarations().at(1);
QVERIFY(dec); QVERIFY(dec);
QCOMPARE(dec->identifier().toString(), QString("test")); QCOMPARE(dec->identifier().toString(), QString("test"));
QCOMPARE(dec->abstractType()->toString(), QString("<class>")); QCOMPARE(dec->abstractType()->toString(), QString("qmlId"));
oldDec = dec; oldDec = dec;
} }
...@@ -170,7 +170,7 @@ void TestDeclarations::testQMLId() ...@@ -170,7 +170,7 @@ void TestDeclarations::testQMLId()
// First declaration, the anonymous class // First declaration, the anonymous class
ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration *>(top->localDeclarations().first()); ClassDeclaration* classDecl = dynamic_cast<ClassDeclaration *>(top->localDeclarations().first());
QVERIFY(classDecl); QVERIFY(classDecl);
QCOMPARE(classDecl->abstractType()->toString(), QString("<class>")); QCOMPARE(classDecl->abstractType()->toString(), QString("qmlId"));
QVERIFY(classDecl->internalContext()); QVERIFY(classDecl->internalContext());
QCOMPARE(classDecl->internalContext()->range(), RangeInRevision(5, 6, 6, 17)); QCOMPARE(classDecl->internalContext()->range(), RangeInRevision(5, 6, 6, 17));
...@@ -178,7 +178,7 @@ void TestDeclarations::testQMLId() ...@@ -178,7 +178,7 @@ void TestDeclarations::testQMLId()
Declaration* dec = top->localDeclarations().at(1); Declaration* dec = top->localDeclarations().at(1);
QVERIFY(dec); QVERIFY(dec);
QCOMPARE(dec->identifier().toString(), QString("test")); QCOMPARE(dec->identifier().toString(), QString("test"));
QCOMPARE(dec->abstractType()->toString(), QString("<class>")); QCOMPARE(dec->abstractType()->toString(), QString("qmlId"));
} }
} }
......
...@@ -113,4 +113,8 @@ Module { ...@@ -113,4 +113,8 @@ Module {
return; return;
} }
} }
test {
id: i_come_from_test_qml
}
} }
import QtQuick 1.1 import QtQuick 1.1
/** /**
* "type" : { "toString" : "<class>" } * "type" : { "toString" : "test" },
* "useCount" : 1
*/ */
Text { Text {
/* /*
* "toString" : "<class> someId", * "toString" : "test someId",
* "useCount" : 3 * "useCount" : 3
*/ */
id: someId id: someId
......
...@@ -41,3 +41,5 @@ var nested_conditions = (simple_compare && b < 3); ...@@ -41,3 +41,5 @@ var nested_conditions = (simple_compare && b < 3);
* "type" : { "toString" : "int" } * "type" : { "toString" : "int" }
*/ */
var simple_shift = (a << 2); var simple_shift = (a << 2);
im_used_in_types_js = "and I'm a string";
...@@ -22,3 +22,8 @@ func(global, i); ...@@ -22,3 +22,8 @@ func(global, i);
*/ */
var line; var line;
online = false; // onFoo replaced by foo when foo is a QML signal 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