aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2016-10-11 14:12:08 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2016-10-31 12:55:58 +0000
commit3925ddc6bfc99849836d427ba65e538370d2e047 (patch)
treef2e43c043feb2b7f50c578bd03cfb1b5decb5013
parent738ed8e5c0de334d780659bbef8a360154a87221 (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.cpp262
-rw-r--r--src/lib/corelib/language/moduleloader.h16
-rw-r--r--src/lib/corelib/language/projectresolver.cpp7
-rw-r--r--src/lib/corelib/language/qualifiedid.h8
-rw-r--r--src/lib/corelib/language/testdata/modulepropertiesingroups.qbs29
-rw-r--r--src/lib/corelib/language/testdata/modules/gmod/gmod1/gmod1.qbs18
-rw-r--r--src/lib/corelib/language/testdata/modules/gmod1/gmod1.qbs12
-rw-r--r--src/lib/corelib/language/testdata/modules/gmod2/gmod2.qbs3
-rw-r--r--src/lib/corelib/language/testdata/modules/gmod3/qmod3.qbs7
-rw-r--r--src/lib/corelib/language/testdata/modules/gmod4/gmod4.qbs8
-rw-r--r--src/lib/corelib/language/tst_language.cpp70
-rw-r--r--src/lib/corelib/language/value.cpp8
-rw-r--r--src/lib/corelib/language/value.h1
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; }