diff --git a/codecompletion/tests/qmlcompletiontest.cpp b/codecompletion/tests/qmlcompletiontest.cpp index 7e32a16efcf877f7e0993536347a436a3ec65402..b7fb20f6dfa8c753d866d5fbf14c474f305641e8 100644 --- a/codecompletion/tests/qmlcompletiontest.cpp +++ b/codecompletion/tests/qmlcompletiontest.cpp @@ -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); diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 5a9b830092703635baf6008a7df95cf8bf6f3ae6..64b4a7e9029b0624e15e3d076f8cea32153ed149 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -34,6 +34,9 @@ #include "parsesession.h" #include "helper.h" +#include +#include + 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(name, RangeInRevision()); + ClassDeclaration* decl = openDeclaration( + 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. diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h index 2744ffe9a137be5a29e448e9d44befa95ad607a2..6567f61058dd64c00c3b2a6a8a1b67ea3f7fb301 100644 --- a/duchain/declarationbuilder.h +++ b/duchain/declarationbuilder.h @@ -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; diff --git a/duchain/parsesession.cpp b/duchain/parsesession.cpp index 3133c804d775b17fad07954589f5e03273558815..fdceb04dc20c2df9065a5d84fd854c70d4f0e802 100644 --- a/duchain/parsesession.cpp +++ b/duchain/parsesession.cpp @@ -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; } } diff --git a/duchain/parsesession.h b/duchain/parsesession.h index 8afc14500e9a97204a20cfdd443a2ed8d9c25415..c4f958c29a33b08b3c099bf6adc7d778bb511bdc 100644 --- a/duchain/parsesession.h +++ b/duchain/parsesession.h @@ -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. */ diff --git a/duchain/tests/testdeclarations.cpp b/duchain/tests/testdeclarations.cpp index 51b90a5a4768caa4155056e14dc84f5b5e5675a3..107b74c532bc097fd9049c3066ec6c4d0116d31a 100644 --- a/duchain/tests/testdeclarations.cpp +++ b/duchain/tests/testdeclarations.cpp @@ -133,7 +133,7 @@ void TestDeclarations::testQMLId() // First declaration, the anonymous class ClassDeclaration* classDecl = dynamic_cast(top->localDeclarations().first()); QVERIFY(classDecl); - QCOMPARE(classDecl->abstractType()->toString(), QString("")); + 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("")); + QCOMPARE(dec->abstractType()->toString(), QString("qmlId")); oldDec = dec; } @@ -170,7 +170,7 @@ void TestDeclarations::testQMLId() // First declaration, the anonymous class ClassDeclaration* classDecl = dynamic_cast(top->localDeclarations().first()); QVERIFY(classDecl); - QCOMPARE(classDecl->abstractType()->toString(), QString("")); + 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("")); + QCOMPARE(dec->abstractType()->toString(), QString("qmlId")); } } diff --git a/tests/files/plugins.qml b/tests/files/plugins.qml index 9b1c0d43dddc5a3aef5414fa7bee7eba2dca55d5..a4c3332f5698e8ed28f2ab0a6ee85c757640431c 100644 --- a/tests/files/plugins.qml +++ b/tests/files/plugins.qml @@ -113,4 +113,8 @@ Module { return; } } + + test { + id: i_come_from_test_qml + } } diff --git a/tests/files/test.qml b/tests/files/test.qml index 4b08b47a0e44c0f7245bb40b313e705ce6fc81eb..86e55d1ace247e82fff041540eb31268a7bf3a22 100644 --- a/tests/files/test.qml +++ b/tests/files/test.qml @@ -1,11 +1,12 @@ import QtQuick 1.1 /** - * "type" : { "toString" : "" } + * "type" : { "toString" : "test" }, + * "useCount" : 1 */ Text { /* - * "toString" : " someId", + * "toString" : "test someId", * "useCount" : 3 */ id: someId diff --git a/tests/files/types.js b/tests/files/types.js index 2428b893f936b35abc5b2a4bc06627e658df0a65..93b3808153392f7465707e4c8f9ac20b893ec70d 100644 --- a/tests/files/types.js +++ b/tests/files/types.js @@ -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"; diff --git a/tests/files/uses.js b/tests/files/uses.js index bfbd6fc3a4a11e2df2d516aa7d7fdc07b7173195..c5ac7e56f76cbd27f1e00dce7a87f648e8b75ebf 100644 --- a/tests/files/uses.js +++ b/tests/files/uses.js @@ -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;