diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2018-01-19 10:58:43 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2018-01-19 10:58:43 +0100 |
commit | 13e8c5371709c9e1c337c664062aec19930c306b (patch) | |
tree | 5cf5ad7eeffbf136f0bfcb17375a118d8160f584 | |
parent | 8ba1aa806bdb313161acad22d9b16c33b295e607 (diff) | |
parent | d3e137c20248f6852a91341782011ca58534ed21 (diff) |
Merge 1.10 into 1.11
Change-Id: Iae805216e202e582923a70733caa842e8070cc7e
-rw-r--r-- | changelogs/changes-1.10.1.md | 1 | ||||
-rw-r--r-- | src/lib/corelib/language/item.h | 1 | ||||
-rw-r--r-- | src/lib/corelib/language/moduleloader.cpp | 62 | ||||
-rw-r--r-- | tests/auto/language/testdata/qbs1275.qbs | 42 | ||||
-rw-r--r-- | tests/auto/language/tst_language.cpp | 16 | ||||
-rw-r--r-- | tests/auto/language/tst_language.h | 1 |
6 files changed, 104 insertions, 19 deletions
diff --git a/changelogs/changes-1.10.1.md b/changelogs/changes-1.10.1.md index 213251f49..45b0cfdb3 100644 --- a/changelogs/changes-1.10.1.md +++ b/changelogs/changes-1.10.1.md @@ -1,4 +1,5 @@ # Important bugfixes +* Fix assertion on project loading (QBS-1275). * Fix crash when the "original" value is misused (QBS-1255). * Fix qtquickcompiler support for qml files in subdirectories (QBS-1261). * Fix GCC support for "bare metal" systems (QBS-1263, QBS-1265). diff --git a/src/lib/corelib/language/item.h b/src/lib/corelib/language/item.h index b86c50a3c..97ca3ad91 100644 --- a/src/lib/corelib/language/item.h +++ b/src/lib/corelib/language/item.h @@ -164,7 +164,6 @@ private: }; inline bool operator<(const Item::Module &m1, const Item::Module &m2) { return m1.name < m2.name; } -inline bool operator==(const Item::Module &m1, const Item::Module &m2) { return m1.item == m2.item; } } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp index 81d1088b5..35d0636b6 100644 --- a/src/lib/corelib/language/moduleloader.cpp +++ b/src/lib/corelib/language/moduleloader.cpp @@ -1000,17 +1000,42 @@ void ModuleLoader::setupProductDependencies(ProductContext *productContext) productContext->project->result->productInfos.insert(item, productContext->info); } -// Non-dependencies first. +// Leaf modules first. static void createSortedModuleList(const Item::Module &parentModule, Item::Modules &modules) { - if (contains(modules, parentModule)) + if (std::find_if(modules.cbegin(), modules.cend(), + [parentModule](const Item::Module &m) { return m.name == parentModule.name;}) + != modules.cend()) { return; + } for (const Item::Module &dep : parentModule.item->modules()) createSortedModuleList(dep, modules); modules.push_back(parentModule); return; } +static Item::Modules modulesSortedByDependency(const Item *productItem) +{ + QBS_CHECK(productItem->type() == ItemType::Product); + Item::Modules sortedModules; + const Item::Modules &unsortedModules = productItem->modules(); + for (const Item::Module &module : unsortedModules) + createSortedModuleList(module, sortedModules); + QBS_CHECK(sortedModules.size() == unsortedModules.size()); + + // Make sure the top-level items stay the same. + for (Item::Module &s : sortedModules) { + for (const Item::Module &u : unsortedModules) { + if (s.name == u.name) { + s.item = u.item; + break; + } + } + } + return sortedModules; +} + + template<typename T> bool insertIntoSet(Set<T> &set, const T &value) { const auto insertionResult = set.insert(value); @@ -1045,21 +1070,22 @@ void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext) Item * const item = productContext->item; - Item::Modules mergedModules; - for (const Item::Module &module : Item::Modules(item->modules())) { - Item::Module mergedModule = module; - ModuleMerger(m_logger, item, mergedModule).start(); - mergedModules << mergedModule; - } - item->setModules(mergedModules); - - // Must happen after all modules have been merged, so needs to be a second loop. - Item::Modules sortedModules; - for (const Item::Module &module : item->modules()) - createSortedModuleList(module, sortedModules); - QBS_CHECK(sortedModules.size() == item->modules().size()); - - for (const Item::Module &module : qAsConst(sortedModules)) { + // It is important that dependent modules are merged after their dependency, because + // the dependent module's merger potentially needs to replace module items that were + // set by the dependency module's merger (namely, scopes of defining items; see + // ModuleMerger::replaceItemInScopes()). + Item::Modules topSortedModules = modulesSortedByDependency(item); + for (Item::Module &module : topSortedModules) + ModuleMerger(m_logger, item, module).start(); + + // Re-sort the modules by name. This is more stable; see QBS-818. + // The list of modules in the product now has the same order as before, + // only the items have been replaced by their merged counterparts. + Item::Modules lexicographicallySortedModules = topSortedModules; + std::sort(lexicographicallySortedModules.begin(), lexicographicallySortedModules.end()); + item->setModules(lexicographicallySortedModules); + + for (const Item::Module &module : topSortedModules) { if (!module.item->isPresentModule()) continue; try { @@ -1101,7 +1127,7 @@ void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext) // Module validation must happen in an extra pass, after all Probes have been resolved. EvalCacheEnabler cacheEnabler(m_evaluator); - for (const Item::Module &module : qAsConst(sortedModules)) { + for (const Item::Module &module : topSortedModules) { if (!module.item->isPresentModule()) continue; try { diff --git a/tests/auto/language/testdata/qbs1275.qbs b/tests/auto/language/testdata/qbs1275.qbs new file mode 100644 index 000000000..898e1f165 --- /dev/null +++ b/tests/auto/language/testdata/qbs1275.qbs @@ -0,0 +1,42 @@ +import qbs + +Project { + Product { + name: "v-bug" + + Export { + Depends { name: "cpp"} + cpp.defines: "" + } + } + + Product { + name: "e-bug" + + Export { Depends { name: "v-bug" } } + } + + Product { + name: "u-bug" + + Export { Depends { name: "c-bug" } } + } + + Product { + name: "c-bug" + + Export { Depends { name: "e-bug" } } + } + + Product + { + name: "H-bug" + + Depends { name: "e-bug" } + Depends { name: "u-bug" } + + Group { + qbs.install: true + } + } +} diff --git a/tests/auto/language/tst_language.cpp b/tests/auto/language/tst_language.cpp index 8124cc2ac..0eb466188 100644 --- a/tests/auto/language/tst_language.cpp +++ b/tests/auto/language/tst_language.cpp @@ -2399,6 +2399,22 @@ void TestLanguage::propertyAssignmentInExportedGroup() QCOMPARE(exceptionCaught, false); } +void TestLanguage::qbs1275() +{ + bool exceptionCaught = false; + try { + defaultParameters.setProjectFilePath(testProject("qbs1275.qbs")); + const TopLevelProjectPtr project = loader->loadProject(defaultParameters); + QVERIFY(!!project); + const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); + QCOMPARE(products.count(), 5); + } catch (const ErrorInfo &e) { + exceptionCaught = true; + qDebug() << e.toString(); + } + QCOMPARE(exceptionCaught, false); +} + void TestLanguage::qbsPropertiesInProjectCondition() { bool exceptionCaught = false; diff --git a/tests/auto/language/tst_language.h b/tests/auto/language/tst_language.h index 2a07e8e42..d12fc898a 100644 --- a/tests/auto/language/tst_language.h +++ b/tests/auto/language/tst_language.h @@ -145,6 +145,7 @@ private slots: void propertiesBlockInGroup(); void propertiesItemInModule(); void propertyAssignmentInExportedGroup(); + void qbs1275(); void qbsPropertiesInProjectCondition(); void qbsPropertyConvenienceOverride(); void relaxedErrorMode(); |