diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2016-10-11 14:12:08 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2016-10-31 12:55:58 +0000 |
commit | 3925ddc6bfc99849836d427ba65e538370d2e047 (patch) | |
tree | f2e43c043feb2b7f50c578bd03cfb1b5decb5013 | |
parent | 738ed8e5c0de334d780659bbef8a360154a87221 (diff) |
Fix module property assignments in Group items
In particular, list properties were quite broken in the Group context.
Task-number: QBS-1005
Task-number: QBS-1026
Change-Id: Id94fee42fdceb28f9a1ae541c293213095d6bb2c
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
-rw-r--r-- | src/lib/corelib/language/moduleloader.cpp | 262 | ||||
-rw-r--r-- | src/lib/corelib/language/moduleloader.h | 16 | ||||
-rw-r--r-- | src/lib/corelib/language/projectresolver.cpp | 7 | ||||
-rw-r--r-- | src/lib/corelib/language/qualifiedid.h | 8 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/modulepropertiesingroups.qbs | 29 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/modules/gmod/gmod1/gmod1.qbs | 18 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/modules/gmod1/gmod1.qbs | 12 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/modules/gmod2/gmod2.qbs | 3 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/modules/gmod3/qmod3.qbs | 7 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/modules/gmod4/gmod4.qbs | 8 | ||||
-rw-r--r-- | src/lib/corelib/language/tst_language.cpp | 70 | ||||
-rw-r--r-- | src/lib/corelib/language/value.cpp | 8 | ||||
-rw-r--r-- | src/lib/corelib/language/value.h | 1 |
13 files changed, 383 insertions, 66 deletions
diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp index 226ea069d..0be8d8cf0 100644 --- a/src/lib/corelib/language/moduleloader.cpp +++ b/src/lib/corelib/language/moduleloader.cpp @@ -658,6 +658,35 @@ static void createSortedModuleList(const Item::Module &parentModule, QVector<Ite return; } +template<typename T> bool insertIntoSet(std::set<T> &set, const T &value) +{ + const auto insertionResult = set.insert(value); + return insertionResult.second; +} + +void ModuleLoader::setupReverseModuleDependencies(const Item::Module &module, + ModuleDependencies &deps, + QualifiedIdSet &seenModules) +{ + if (!insertIntoSet(seenModules, module.name)) + return; + const Item::Modules &modules = module.item->modules(); + for (auto it = modules.begin(); it != modules.end(); ++it) { + deps[it->name].insert(module.name); + setupReverseModuleDependencies(*it, deps, seenModules); + } +} + +ModuleLoader::ModuleDependencies ModuleLoader::setupReverseModuleDependencies(const Item *product) +{ + ModuleDependencies deps; + QualifiedIdSet seenModules; + const Item::Modules &modules = product->modules(); + for (auto it = modules.begin(); it != modules.end(); ++it) + setupReverseModuleDependencies(*it, deps, seenModules); + return deps; +} + void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext) { if (productContext->info.hasError) @@ -730,9 +759,13 @@ void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext) copyGroupsFromModulesToProduct(*productContext); + ModuleDependencies reverseModuleDeps; foreach (Item *child, item->children()) { - if (child->type() == ItemType::Group) - handleGroup(productContext, child); + if (child->type() == ItemType::Group) { + if (reverseModuleDeps.isEmpty()) + reverseModuleDeps = setupReverseModuleDependencies(item); + handleGroup(productContext, child, reverseModuleDeps); + } } productContext->project->result->productInfos.insert(item, productContext->info); } @@ -789,10 +822,11 @@ void ModuleLoader::handleSubProject(ModuleLoader::ProjectContext *projectContext QSet<QString>(referencedFilePaths) << subProjectFilePath); } -void ModuleLoader::handleGroup(ProductContext *productContext, Item *groupItem) +void ModuleLoader::handleGroup(ProductContext *productContext, Item *groupItem, + const ModuleDependencies &reverseDepencencies) { checkCancelation(); - propagateModulesFromProduct(productContext, groupItem); + propagateModulesFromProduct(productContext, groupItem, reverseDepencencies); checkItemCondition(groupItem); } @@ -935,9 +969,37 @@ void ModuleLoader::mergeExportItems(const ProductContext &productContext) pmi.exportItem = merged; } -void ModuleLoader::propagateModulesFromProduct(ProductContext *productContext, Item *groupItem) +bool ModuleLoader::isSomeModulePropertySet(const Item *item) +{ + for (auto it = item->properties().cbegin(); it != item->properties().cend(); ++it) { + switch (it.value()->type()) { + case Value::JSSourceValueType: + if (item->type() == ItemType::ModuleInstance) { + if (m_logger.traceEnabled()) { + m_logger.qbsTrace() << "[LDR] scope adaptation for group module items " + "necessary because of property " << it.key(); + } + return true; + } + break; + case Value::ItemValueType: + if (isSomeModulePropertySet(it.value().staticCast<ItemValue>()->item())) + return true; + break; + default: + break; + } + } + return false; +} + +void ModuleLoader::propagateModulesFromProduct(ProductContext *productContext, Item *groupItem, + const ModuleDependencies &reverseDepencencies) { QBS_CHECK(groupItem->type() == ItemType::Group); + QHash<QualifiedId, Item *> moduleInstancesForGroup; + + // Step 1: Instantiate the product's modules for the group. for (Item::Modules::const_iterator it = productContext->item->modules().constBegin(); it != productContext->item->modules().constEnd(); ++it) { @@ -945,17 +1007,201 @@ void ModuleLoader::propagateModulesFromProduct(ProductContext *productContext, I Item *targetItem = moduleInstanceItem(groupItem, m.name); targetItem->setPrototype(m.item); targetItem->setType(ItemType::ModuleInstance); - targetItem->setScope(m.item->scope()); - targetItem->setModules(m.item->modules()); + + Item * const moduleScope = Item::create(targetItem->pool(), ItemType::Scope); + moduleScope->setFile(groupItem->file()); + moduleScope->setProperties(m.item->scope()->properties()); // "project", "product", ids + moduleScope->setScope(groupItem); + targetItem->setScope(moduleScope); + + targetItem->setFile(m.item->file()); // "parent" should point to the group/artifact parent targetItem->setParent(groupItem->parent()); // the outer item of a module is the product's instance of it - targetItem->setOuterItem(m.item); // ### Is this always the same as the scope item? + targetItem->setOuterItem(m.item); m.item = targetItem; groupItem->addModule(m); + moduleInstancesForGroup.insert(m.name, targetItem); + } + + // Step 2: Make the inter-module references point to the instances created in step 1. + for (auto it = groupItem->modules().cbegin(); it != groupItem->modules().cend(); ++it) { + Item::Modules adaptedModules; + const Item::Modules &oldModules = it->item->prototype()->modules(); + for (auto depIt = oldModules.begin(); depIt != oldModules.end(); ++depIt) { + Item::Module depMod = *depIt; + depMod.item = moduleInstancesForGroup.value(depIt->name); + adaptedModules << depMod; + if (depMod.name.first() == it->name.first()) + continue; + const ItemValuePtr &modulePrefix = groupItem->itemProperty(depMod.name.first()); + QBS_CHECK(modulePrefix); + it->item->setProperty(depMod.name.first(), modulePrefix); + } + it->item->setModules(adaptedModules); + } + + if (!isSomeModulePropertySet(groupItem)) + return; + + // Step 3: Adapt defining items in values. This is potentially necessary if module properties + // get assigned on the group level. + const Item::Modules &groupModules = groupItem->modules(); + for (auto modIt = groupModules.begin(); modIt != groupModules.end(); ++modIt) { + const QualifiedIdSet &dependents = reverseDepencencies.value(modIt->name); + Item::Modules dependentModules; + dependentModules.reserve(dependents.size()); + for (auto depIt = dependents.begin(); depIt != dependents.end(); ++depIt) { + Item * const itemOfDependent = moduleInstancesForGroup.value(*depIt); + QBS_CHECK(itemOfDependent); + Item::Module depMod; + depMod.name = *depIt; + depMod.item = itemOfDependent; + dependentModules << depMod; + } + adjustDefiningItemsInGroupModuleInstances(*modIt, dependentModules); + } +} + +void ModuleLoader::adjustDefiningItemsInGroupModuleInstances(const Item::Module &module, + const Item::Modules &dependentModules) +{ + // There are three cases: + // a) The defining item is the "main" module instance, i.e. the one instantiated in the + // product directly. + // b) The defining item refers to the module prototype. + // c) The defining item is a different instance of the module, i.e. it was instantiated + // in some other module. + // TODO: Needs adjustments for nested groups. + + QHash<Item *, Item *> definingItemReplacements; + const Item::PropertyMap &protoProps = module.item->prototype()->properties(); + for (auto propIt = protoProps.begin(); propIt != protoProps.end(); ++propIt) { + const QString &propName = propIt.key(); + + // Module properties assigned in the group are not relevant here, as nothing + // gets inherited in that case. In particular, setting a list property + // overwrites the value from the product's (merged) instance completely, + // rather than appending to it (concatenation happens via outer.concat()). + if (module.item->properties().contains(propIt.key())) + continue; + + if (propIt.value()->type() != Value::JSSourceValueType) + continue; + + const PropertyDeclaration &propDecl = module.item->propertyDeclaration(propName); + bool hasDefiningItem = false; + for (ValuePtr v = propIt.value(); v && !hasDefiningItem; v = v->next()) + hasDefiningItem = v->definingItem(); + if (!hasDefiningItem) { + QBS_CHECK(propDecl.isScalar()); + continue; + } + + const ValuePtr clonedValue = propIt.value()->clone(); + for (ValuePtr v = clonedValue; v; v = v->next()) { + QBS_CHECK(v->definingItem()); + + Item *& replacement = definingItemReplacements[v->definingItem()]; + if (v->definingItem() == module.item->prototype()) { + // Case a) + // For values whose defining item is the product's instance, we take its scope + // and replace references to module instances with those from the + // group's instance. This handles cases like the following: + // Product { + // name: "theProduct" + // aModule.listProp: [name, otherModule.stringProp] + // Group { name: "theGroup"; otherModule.stringProp: name } + // ... + // } + // In the above example, aModule.listProp is set to ["theProduct", "theGroup"] + // (plus potential values from the prototype and other module instances, + // which are different Value objects in the "next chain"). + if (!replacement) { + replacement = Item::create(v->definingItem()->pool()); + Item * const scope = Item::create(v->definingItem()->pool(), ItemType::Scope); + scope->setProperties(module.item->scope()->properties()); + Item * const scopeScope + = Item::create(v->definingItem()->pool(), ItemType::Scope); + scopeScope->setProperties(v->definingItem()->scope()->scope()->properties()); + scope->setScope(scopeScope); + replacement->setScope(scope); + const Item::PropertyMap &groupScopeProperties + = module.item->scope()->scope()->properties(); + for (auto propIt = groupScopeProperties.begin(); + propIt != groupScopeProperties.end(); ++propIt) { + if (propIt.value()->type() == Value::ItemValueType) + scopeScope->setProperty(propIt.key(), propIt.value()); + } + } + replacement->setPropertyDeclaration(propName, propDecl); + replacement->setProperty(propName, v); + } else if (v->definingItem()->type() == ItemType::Module) { + // Case b) + // For values whose defining item is the module prototype, we change the scope to + // the group's instance, analogous to what we do in + // ModuleMerger::appendPrototypeValueToNextChain(). + QBS_CHECK(!propDecl.isScalar()); + QBS_CHECK(!v->next()); + Item *& replacement = definingItemReplacements[v->definingItem()]; + if (!replacement) { + replacement = Item::create(v->definingItem()->pool(), + ItemType::Module); + replacement->setScope(module.item); + } + if (m_logger.traceEnabled()) { + m_logger.qbsTrace() << "[LDR] replacing defining item for prototype; module is " + << module.name.toString() << module.item + << ", property is " << propName + << ", old defining item was " << v->definingItem() + << " with scope" << v->definingItem()->scope() + << ", new defining item is" << replacement + << " with scope" << replacement->scope() + << ", value source code is " + << v.staticCast<JSSourceValue>()->sourceCode().toString(); + } + replacement->setPropertyDeclaration(propName, propDecl); + replacement->setProperty(propName, v); + } else { + // Look for instance scopes of other module instances in defining items and + // replace the affected values. + // This is case c) as introduced above. See ModuleMerger::replaceItemInScopes() + // for a detailed explanation. + + QBS_CHECK(v->definingItem()->scope() && v->definingItem()->scope()->scope()); + bool found = false; + for (auto depIt = dependentModules.cbegin(); depIt != dependentModules.cend(); + ++depIt) { + const Item::Module &depMod = *depIt; + if (v->definingItem()->scope()->scope() != depMod.item->prototype()) + continue; + + found = true; + Item *& replacement = definingItemReplacements[v->definingItem()]; + if (!replacement) { + replacement = Item::create(v->definingItem()->pool()); + replacement->setProperties(v->definingItem()->properties()); + foreach (const auto &decl, v->definingItem()->propertyDeclarations()) + replacement->setPropertyDeclaration(decl.name(), decl); + replacement->setPrototype(v->definingItem()->prototype()); + replacement->setScope(Item::create(v->definingItem()->pool())); + replacement->scope()->setScope(depMod.item); + } + if (m_logger.traceEnabled()) { + m_logger.qbsTrace() << "[LDR] reset instance scope of module " + << depMod.name.toString() << " in property " + << propName << " of module " << module.name; + } + } + QBS_CHECK(found); + } + QBS_CHECK(replacement); + v->setDefiningItem(replacement); + } + module.item->setProperty(propName, clonedValue); } } diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h index 44f68e8f5..dc10a75b9 100644 --- a/src/lib/corelib/language/moduleloader.h +++ b/src/lib/corelib/language/moduleloader.h @@ -199,9 +199,19 @@ private: void initProductProperties(const ProductContext &product); void handleSubProject(ProjectContext *projectContext, Item *projectItem, const QSet<QString> &referencedFilePaths); - void handleGroup(ProductContext *productContext, Item *groupItem); + + using ModuleDependencies = QHash<QualifiedId, QualifiedIdSet>; + void setupReverseModuleDependencies(const Item::Module &module, ModuleDependencies &deps, + QualifiedIdSet &seenModules); + ModuleDependencies setupReverseModuleDependencies(const Item *product); + void handleGroup(ProductContext *productContext, Item *groupItem, + const ModuleDependencies &reverseDepencencies); + void propagateModulesFromProduct(ProductContext *productContext, Item *groupItem, + const ModuleDependencies &reverseDepencencies); + void adjustDefiningItemsInGroupModuleInstances(const Item::Module &module, + const Item::Modules &dependentModules); + void mergeExportItems(const ProductContext &productContext); - void propagateModulesFromProduct(ProductContext *productContext, Item *groupItem); void resolveDependencies(DependsContext *dependsContext, Item *item); class ItemModuleList; void resolveDependsItem(DependsContext *dependsContext, Item *parentItem, Item *dependsItem, @@ -247,6 +257,8 @@ private: ProbeConstPtr findCurrentProbe(const CodeLocation &location, bool condition, const QVariantMap &initialProperties) const; + bool isSomeModulePropertySet(const Item *item); + ScriptEngine *m_engine; ItemPool *m_pool; Logger m_logger; diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp index bfb2eb74c..4d00365be 100644 --- a/src/lib/corelib/language/projectresolver.cpp +++ b/src/lib/corelib/language/projectresolver.cpp @@ -54,7 +54,6 @@ #include <QQueue> #include <algorithm> -#include <set> namespace qbs { namespace Internal { @@ -725,12 +724,6 @@ void ProjectResolver::resolveRule(Item *item, ProjectContext *projectContext) projectContext->rules += rule; } -class QualifiedIdSet : public std::set<QualifiedId> -{ -public: - typedef std::pair<iterator, bool> InsertResult; -}; - void ProjectResolver::resolveRuleArtifact(const RulePtr &rule, Item *item) { RuleArtifactPtr artifact = RuleArtifact::create(); diff --git a/src/lib/corelib/language/qualifiedid.h b/src/lib/corelib/language/qualifiedid.h index f0f68392e..c1f51bb15 100644 --- a/src/lib/corelib/language/qualifiedid.h +++ b/src/lib/corelib/language/qualifiedid.h @@ -33,6 +33,8 @@ #include <QStringList> +#include <set> + namespace qbs { namespace Internal { @@ -49,6 +51,12 @@ public: bool operator<(const QualifiedId &a, const QualifiedId &b); +class QualifiedIdSet : public std::set<QualifiedId> +{ +public: + typedef std::pair<iterator, bool> InsertResult; +}; + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/testdata/modulepropertiesingroups.qbs b/src/lib/corelib/language/testdata/modulepropertiesingroups.qbs index 22fb750e4..6b1976e10 100644 --- a/src/lib/corelib/language/testdata/modulepropertiesingroups.qbs +++ b/src/lib/corelib/language/testdata/modulepropertiesingroups.qbs @@ -4,33 +4,38 @@ Project { Product { name: "grouptest" - Depends { name: "gmod1" } - Depends { name: "dummyqt.core" } + Depends { name: "gmod.gmod1" } + Depends { name: "gmod3" } + Depends { name: "gmod4" } - gmod1.listProp2: ["product", gmod1.stringProp] - gmod1.p1: 1 + gmod.gmod1.gmod1_list2: base.concat([name, gmod.gmod1.gmod1_string]) + gmod.gmod1.gmod1_list3: ["product"] + gmod.gmod1.p1: 1 // TODO: Also test nested groups in >= 1.7 Group { name: "g1" files: ["Banana"] - gmod1.stringProp: "g1" - gmod1.listProp2: ["g1"] - gmod1.p2: 2 + gmod.gmod1.gmod1_string: name + gmod.gmod1.gmod1_list2: outer.concat([name]) + gmod.gmod1.p2: 2 gmod2.prop: 1 - dummyqt.core.zort: "X" + gmod2.commonName: "g1" + gmod3.gmod3_string: "g1_gmod3" + gmod4.gmod4_string: "g1_gmod4" } Group { name: "g2" files: ["zort"] - gmod1.stringProp: "g2" - gmod1.listProp2: ["g2"] - gmod1.p1: 2 - gmod1.p2: 4 + gmod.gmod1.gmod1_string: name + gmod.gmod1.p1: 2 + gmod.gmod1.p2: 4 gmod2.prop: 2 + gmod3.gmod3_string: name + "_gmod3" + gmod4.gmod4_string: name + "_gmod4" } } } diff --git a/src/lib/corelib/language/testdata/modules/gmod/gmod1/gmod1.qbs b/src/lib/corelib/language/testdata/modules/gmod/gmod1/gmod1.qbs new file mode 100644 index 000000000..d3bb92fff --- /dev/null +++ b/src/lib/corelib/language/testdata/modules/gmod/gmod1/gmod1.qbs @@ -0,0 +1,18 @@ +import qbs + +Module { + Depends { name: "gmod2" } + Depends { name: "gmod4" } + property stringList gmod1_list1: ["gmod1_list1_proto", gmod1_string] + property stringList gmod1_list2: ["gmod1_list2_proto"] + property stringList gmod1_list3: [gmod1_string] + property string gmod1_string: "gmod1_string_proto" + property string commonName: "commonName_in_gmod1" + property int depProp: gmod2.prop + property int p0: p1 + p2 + property int p1: 0 + property int p2: 0 + + gmod2.gmod2_string: gmod1_string + gmod2.gmod2_list: [gmod1_string, commonName] +} diff --git a/src/lib/corelib/language/testdata/modules/gmod1/gmod1.qbs b/src/lib/corelib/language/testdata/modules/gmod1/gmod1.qbs deleted file mode 100644 index 416372e3d..000000000 --- a/src/lib/corelib/language/testdata/modules/gmod1/gmod1.qbs +++ /dev/null @@ -1,12 +0,0 @@ -import qbs - -Module { - Depends { name: "gmod2" } - property stringList listProp1: ["prototype", stringProp] - property stringList listProp2: ["prototype"] - property string stringProp: "prototype" - property int depProp: gmod2.prop - property int p0: p1 + p2 - property int p1: 0 - property int p2: 0 -} diff --git a/src/lib/corelib/language/testdata/modules/gmod2/gmod2.qbs b/src/lib/corelib/language/testdata/modules/gmod2/gmod2.qbs index 208f7330d..e221f50b2 100644 --- a/src/lib/corelib/language/testdata/modules/gmod2/gmod2.qbs +++ b/src/lib/corelib/language/testdata/modules/gmod2/gmod2.qbs @@ -2,4 +2,7 @@ import qbs Module { property int prop: 0 + property string gmod2_string: "gmod2_string_proto" + property string commonName: "commonName_in_gmod2" + property stringList gmod2_list: ["gmod2_list_proto"] } diff --git a/src/lib/corelib/language/testdata/modules/gmod3/qmod3.qbs b/src/lib/corelib/language/testdata/modules/gmod3/qmod3.qbs new file mode 100644 index 000000000..1c8704b5d --- /dev/null +++ b/src/lib/corelib/language/testdata/modules/gmod3/qmod3.qbs @@ -0,0 +1,7 @@ +import qbs + +Module { + Depends { name: "gmod2" } + property string gmod3_string: "gmod3_string_proto" + gmod2.gmod2_list: [gmod3_string] +} diff --git a/src/lib/corelib/language/testdata/modules/gmod4/gmod4.qbs b/src/lib/corelib/language/testdata/modules/gmod4/gmod4.qbs new file mode 100644 index 000000000..c06f4e965 --- /dev/null +++ b/src/lib/corelib/language/testdata/modules/gmod4/gmod4.qbs @@ -0,0 +1,8 @@ +import qbs + +Module { + Depends { name: "gmod2" } + Depends { name: "gmod3" } + property string gmod4_string: "gmod4_string_proto" + gmod2.gmod2_list: [gmod4_string + "_" + gmod3.gmod3_string] +} diff --git a/src/lib/corelib/language/tst_language.cpp b/src/lib/corelib/language/tst_language.cpp index 82ca99194..1d876623e 100644 --- a/src/lib/corelib/language/tst_language.cpp +++ b/src/lib/corelib/language/tst_language.cpp @@ -1132,48 +1132,68 @@ void TestLanguage::modulePropertiesInGroups() const QVariantMap productProps = product->moduleProperties->value(); PropertyFinder pf; - const auto &productListProp1 = pf.propertyValue(productProps, "gmod1", "listProp1") + const auto &productGmod1List1 = pf.propertyValue(productProps, "gmod.gmod1", "gmod1_list1") .toStringList(); - QCOMPARE(productListProp1, QStringList() << "prototype" << "prototype"); - const auto &productListProp2 = pf.propertyValue(productProps, "gmod1", "listProp2") + QCOMPARE(productGmod1List1, QStringList() << "gmod1_list1_proto" << "gmod1_string_proto"); + const auto &productGmod1List2 = pf.propertyValue(productProps, "gmod.gmod1", "gmod1_list2") .toStringList(); - QCOMPARE(productListProp2, QStringList() << "product" << "prototype" << "prototype"); - const int productP0 = pf.propertyValue(productProps, "gmod1", "p0").toInt(); + QCOMPARE(productGmod1List2, QStringList() << "grouptest" << "gmod1_string_proto" + << "gmod1_list2_proto"); + const auto &productGmod1List3 = pf.propertyValue(productProps, "gmod.gmod1", "gmod1_list3") + .toStringList(); + QCOMPARE(productGmod1List3, QStringList() << "product" << "gmod1_string_proto"); + const int productP0 = pf.propertyValue(productProps, "gmod.gmod1", "p0").toInt(); QCOMPARE(productP0, 1); - const int productDepProp = pf.propertyValue(productProps, "gmod1", "depProp").toInt(); + const int productDepProp = pf.propertyValue(productProps, "gmod.gmod1", "depProp").toInt(); QCOMPARE(productDepProp, 0); + const auto &productGmod2String = pf.propertyValue(productProps, "gmod2", "gmod2_string") + .toString(); + QCOMPARE(productGmod2String, QString("gmod1_string_proto")); + const auto &productGmod2List = pf.propertyValue(productProps, "gmod2", "gmod2_list") + .toStringList(); + QCOMPARE(productGmod2List, QStringList() << "gmod1_string_proto" << "commonName_in_gmod1" + << "gmod4_string_proto_gmod3_string_proto" << "gmod3_string_proto" + << "gmod2_list_proto"); const QVariantMap g1Props = g1->properties->value(); - const auto &g1ListProp1 = pf.propertyValue(g1Props, "gmod1", "listProp1") + const auto &g1Gmod1List1 = pf.propertyValue(g1Props, "gmod.gmod1", "gmod1_list1") .toStringList(); - QCOMPARE(g1ListProp1, QStringList() << "prototype" << "g1"); - const auto &g1ListProp2 = pf.propertyValue(g1Props, "gmod1", "listProp2") + QCOMPARE(g1Gmod1List1, QStringList() << "gmod1_list1_proto" << "g1"); + const auto &g1Gmod1List2 = pf.propertyValue(g1Props, "gmod.gmod1", "gmod1_list2") .toStringList(); - QEXPECT_FAIL(0, "QBS-1005", Continue); - QCOMPARE(g1ListProp2, QStringList() << "product" << "g1" << "prototype"); - const int g1P0 = pf.propertyValue(g1Props, "gmod1", "p0").toInt(); + QCOMPARE(g1Gmod1List2, QStringList() << "grouptest" << "gmod1_string_proto" + << "gmod1_list2_proto" << "g1"); + const auto &g1Gmod1List3 = pf.propertyValue(g1Props, "gmod.gmod1", "gmod1_list3") + .toStringList(); + QCOMPARE(g1Gmod1List3, QStringList() << "product" << "g1"); + const int g1P0 = pf.propertyValue(g1Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g1P0, 3); - const int g1DepProp = pf.propertyValue(g1Props, "gmod1", "depProp").toInt(); - QEXPECT_FAIL(0, "QBS-1005", Continue); + const int g1DepProp = pf.propertyValue(g1Props, "gmod.gmod1", "depProp").toInt(); QCOMPARE(g1DepProp, 1); - const auto &g1DummyCFlags = pf.propertyValue(g1Props, "dummy", "cFlags") + const auto &g1Gmod2String = pf.propertyValue(g1Props, "gmod2", "gmod2_string").toString(); + QCOMPARE(g1Gmod2String, QString("g1")); + const auto &g1Gmod2List = pf.propertyValue(g1Props, "gmod2", "gmod2_list") .toStringList(); - QEXPECT_FAIL(0, "QBS-1005", Continue); - QCOMPARE(g1DummyCFlags, QStringList("X")); + QCOMPARE(g1Gmod2List, QStringList() << "g1" << "commonName_in_gmod1" << "g1_gmod4_g1_gmod3" + << "g1_gmod3" << "gmod2_list_proto"); const QVariantMap g2Props = g2->properties->value(); - const auto &g2ListProp1 = pf.propertyValue(g2Props, "gmod1", "listProp1") + const auto &g2Gmod1List1 = pf.propertyValue(g2Props, "gmod.gmod1", "gmod1_list1") .toStringList(); - QCOMPARE(g2ListProp1, QStringList() << "prototype" << "g2"); - const auto &g2ListProp2 = pf.propertyValue(g2Props, "gmod1", "listProp2") + QCOMPARE(g2Gmod1List1, QStringList() << "gmod1_list1_proto" << "g2"); + const auto &g2Gmod1List2 = pf.propertyValue(g2Props, "gmod.gmod1", "gmod1_list2") .toStringList(); - QEXPECT_FAIL(0, "QBS-1005", Continue); - QCOMPARE(g2ListProp2, QStringList() << "product" << "g2" << "prototype"); - const int g2P0 = pf.propertyValue(g2Props, "gmod1", "p0").toInt(); + QCOMPARE(g2Gmod1List2, QStringList() << "grouptest" << "g2" << "gmod1_list2_proto"); + const int g2P0 = pf.propertyValue(g2Props, "gmod.gmod1", "p0").toInt(); QCOMPARE(g2P0, 6); - const int g2DepProp = pf.propertyValue(g2Props, "gmod1", "depProp").toInt(); - QEXPECT_FAIL(0, "QBS-1005", Continue); + const int g2DepProp = pf.propertyValue(g2Props, "gmod.gmod1", "depProp").toInt(); QCOMPARE(g2DepProp, 2); + const auto &g2Gmod2String = pf.propertyValue(g2Props, "gmod2", "gmod2_string").toString(); + QCOMPARE(g2Gmod2String, QString("g2")); + const auto &g2Gmod2List = pf.propertyValue(g2Props, "gmod2", "gmod2_list") + .toStringList(); + QCOMPARE(g2Gmod2List, QStringList() << "g2" << "commonName_in_gmod1" << "g2_gmod4_g2_gmod3" + << "g2_gmod3" << "gmod2_list_proto"); } catch (const ErrorInfo &e) { exceptionCaught = true; qDebug() << e.toString(); diff --git a/src/lib/corelib/language/value.cpp b/src/lib/corelib/language/value.cpp index d312a52e8..54bbc9a4e 100644 --- a/src/lib/corelib/language/value.cpp +++ b/src/lib/corelib/language/value.cpp @@ -43,6 +43,14 @@ Value::Value(Type t, bool createdByPropertiesBlock) { } +Value::Value(const Value &other) + : m_type(other.m_type), + m_definingItem(other.m_definingItem), + m_next(other.m_next ? other.m_next->clone() : ValuePtr()), + m_createdByPropertiesBlock(other.m_createdByPropertiesBlock) +{ +} + Value::~Value() { } diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h index 831e0d066..9afaeb0a5 100644 --- a/src/lib/corelib/language/value.h +++ b/src/lib/corelib/language/value.h @@ -51,6 +51,7 @@ public: }; Value(Type t, bool createdByPropertiesBlock); + Value(const Value &other); virtual ~Value(); Type type() const { return m_type; } |