diff options
9 files changed, 70 insertions, 11 deletions
diff --git a/src/lib/language/moduleloader.cpp b/src/lib/language/moduleloader.cpp index 20e611d9b..7f51bc422 100644 --- a/src/lib/language/moduleloader.cpp +++ b/src/lib/language/moduleloader.cpp @@ -111,13 +111,14 @@ ModuleLoaderResult ModuleLoader::load(const QString &filePath, if (wrapWithProjectItem && root->typeName() != QLatin1String("Project")) root = wrapWithProject(root); - handleProject(&result, root); + handleProject(&result, root, QSet<QString>() << QDir::cleanPath(filePath)); result.root = root; result.qbsFiles = m_reader->filesRead(); return result; } -void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, Item *item) +void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, Item *item, + const QSet<QString> &referencedFilePaths) { if (!checkItemCondition(item)) return; @@ -141,10 +142,10 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, Item *item) if (child->typeName() == QLatin1String("Product")) { handleProduct(&projectContext, child); } else if (child->typeName() == QLatin1String("SubProject")) { - handleSubProject(&projectContext, child); + handleSubProject(&projectContext, child, referencedFilePaths); } else if (child->typeName() == QLatin1String("Project")) { copyProperties(item, child); - handleProject(loadResult, child); + handleProject(loadResult, child, referencedFilePaths); } } @@ -152,6 +153,9 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, Item *item) const QStringList refs = toStringList(m_evaluator->property(item, "references")); foreach (const QString &filePath, refs) { const QString absReferencePath = FileInfo::resolvePath(projectFileDirPath, filePath); + if (referencedFilePaths.contains(absReferencePath)) + throw ErrorInfo(Tr::tr("Cycle detected while referencing file '%1'.").arg(filePath), + item->property(QLatin1String("references"))->location()); Item *subItem = m_reader->readFile(absReferencePath); subItem->setScope(projectContext.scope); subItem->setParent(projectContext.item); @@ -162,7 +166,8 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult, Item *item) handleProduct(&projectContext, subItem); } else if (subItem->typeName() == "Project") { copyProperties(item, subItem); - handleProject(loadResult, subItem); + handleProject(loadResult, subItem, + QSet<QString>(referencedFilePaths) << absReferencePath); } else { throw ErrorInfo(Tr::tr("The top-level item of a file in a \"references\" list must be " "a Product or a Project, but it is \"%1\".").arg(subItem->typeName()), @@ -208,7 +213,8 @@ void ModuleLoader::handleProduct(ProjectContext *projectContext, Item *item) projectContext->result->productInfos.insert(item, productContext.info); } -void ModuleLoader::handleSubProject(ModuleLoader::ProjectContext *projectContext, Item *item) +void ModuleLoader::handleSubProject(ModuleLoader::ProjectContext *projectContext, Item *item, + const QSet<QString> &referencedFilePaths) { if (m_logger.traceEnabled()) m_logger.qbsTrace() << "[MODLDR] handleSubProject " << item->file()->filePath(); @@ -221,8 +227,12 @@ void ModuleLoader::handleSubProject(ModuleLoader::ProjectContext *projectContext return; const QString projectFileDirPath = FileInfo::path(item->file()->filePath()); - QString subProjectFilePath = m_evaluator->property(item, "filePath").toString(); - subProjectFilePath = FileInfo::resolvePath(projectFileDirPath, subProjectFilePath); + const QString relativeFilePath = m_evaluator->property(item, + QLatin1String("filePath")).toString(); + QString subProjectFilePath = FileInfo::resolvePath(projectFileDirPath, relativeFilePath); + if (referencedFilePaths.contains(subProjectFilePath)) + throw ErrorInfo(Tr::tr("Cycle detected while loading subproject file '%1'.") + .arg(relativeFilePath), item->location()); Item *loadedItem = m_reader->readFile(subProjectFilePath); if (loadedItem->typeName() == QLatin1String("Product")) loadedItem = wrapWithProject(loadedItem); @@ -251,7 +261,8 @@ void ModuleLoader::handleSubProject(ModuleLoader::ProjectContext *projectContext Item::addChild(item, loadedItem); item->setScope(projectContext->scope); - handleProject(projectContext->result, loadedItem); + handleProject(projectContext->result, loadedItem, + QSet<QString>(referencedFilePaths) << subProjectFilePath); } void ModuleLoader::createAdditionalModuleInstancesInProduct(ProductContext *productContext) diff --git a/src/lib/language/moduleloader.h b/src/lib/language/moduleloader.h index 6c196c414..e30d6bd4f 100644 --- a/src/lib/language/moduleloader.h +++ b/src/lib/language/moduleloader.h @@ -145,9 +145,11 @@ private: typedef QPair<Item *, ModuleLoaderResult::ProductInfo::Dependency> ProductDependencyResult; typedef QList<ProductDependencyResult> ProductDependencyResults; - void handleProject(ModuleLoaderResult *loadResult, Item *item); + void handleProject(ModuleLoaderResult *loadResult, Item *item, + const QSet<QString> &referencedFilePaths); void handleProduct(ProjectContext *projectContext, Item *item); - void handleSubProject(ProjectContext *projectContext, Item *item); + void handleSubProject(ProjectContext *projectContext, Item *item, + const QSet<QString> &referencedFilePaths); void createAdditionalModuleInstancesInProduct(ProductContext *productContext); void handleGroup(ProductContext *productContext, Item *group); void handleArtifact(ProductContext *productContext, Item *item); diff --git a/src/lib/language/testdata/erroneous/references_cycle.qbs b/src/lib/language/testdata/erroneous/references_cycle.qbs new file mode 100644 index 000000000..6d0960f09 --- /dev/null +++ b/src/lib/language/testdata/erroneous/references_cycle.qbs @@ -0,0 +1,6 @@ +import qbs 1.0 + +Project { + references: ["references_cycle2.qbs"] +} + diff --git a/src/lib/language/testdata/erroneous/references_cycle2.qbs b/src/lib/language/testdata/erroneous/references_cycle2.qbs new file mode 100644 index 000000000..0b0d2734d --- /dev/null +++ b/src/lib/language/testdata/erroneous/references_cycle2.qbs @@ -0,0 +1,6 @@ +import qbs 1.0 + +Project { + references: ["references_cycle3.qbs"] +} + diff --git a/src/lib/language/testdata/erroneous/references_cycle3.qbs b/src/lib/language/testdata/erroneous/references_cycle3.qbs new file mode 100644 index 000000000..2a237d154 --- /dev/null +++ b/src/lib/language/testdata/erroneous/references_cycle3.qbs @@ -0,0 +1,6 @@ +import qbs 1.0 + +Project { + references: ["references_cycle.qbs"] +} + diff --git a/src/lib/language/testdata/erroneous/subproject_cycle.qbs b/src/lib/language/testdata/erroneous/subproject_cycle.qbs new file mode 100644 index 000000000..0a9cd289f --- /dev/null +++ b/src/lib/language/testdata/erroneous/subproject_cycle.qbs @@ -0,0 +1,8 @@ +import qbs 1.0 + +Project { + SubProject { + filePath: "subproject_cycle2.qbs" + } +} + diff --git a/src/lib/language/testdata/erroneous/subproject_cycle2.qbs b/src/lib/language/testdata/erroneous/subproject_cycle2.qbs new file mode 100644 index 000000000..ab92d76dd --- /dev/null +++ b/src/lib/language/testdata/erroneous/subproject_cycle2.qbs @@ -0,0 +1,8 @@ +import qbs 1.0 + +Project { + SubProject { + filePath: "subproject_cycle3.qbs" + } +} + diff --git a/src/lib/language/testdata/erroneous/subproject_cycle3.qbs b/src/lib/language/testdata/erroneous/subproject_cycle3.qbs new file mode 100644 index 000000000..af1e50f5a --- /dev/null +++ b/src/lib/language/testdata/erroneous/subproject_cycle3.qbs @@ -0,0 +1,8 @@ +import qbs 1.0 + +Project { + SubProject { + filePath: "subproject_cycle.qbs" + } +} + diff --git a/src/lib/language/tst_language.cpp b/src/lib/language/tst_language.cpp index 5d75ac339..4f953de2f 100644 --- a/src/lib/language/tst_language.cpp +++ b/src/lib/language/tst_language.cpp @@ -318,6 +318,10 @@ void TestLanguage::erroneousFiles_data() << "Cannot reuse the name of built-in extension 'TextFile'."; QTest::newRow("throw_in_property_binding") << "something is wrong"; + QTest::newRow("references_cycle") + << "Cycle detected while referencing file 'references_cycle.qbs'."; + QTest::newRow("subproject_cycle") + << "Cycle detected while loading subproject file 'subproject_cycle.qbs'."; } void TestLanguage::erroneousFiles() |
