aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/language
diff options
context:
space:
mode:
authorJoerg Bornemann <joerg.bornemann@theqtcompany.com>2015-01-19 11:57:40 +0100
committerJoerg Bornemann <joerg.bornemann@theqtcompany.com>2015-01-20 12:06:01 +0100
commit0d477159e67ef4e0dd665b8c5ba8850b11145afe (patch)
treeb9d1163c7d63b46378011d1bc67b91dda94e9ced /src/lib/corelib/language
parent1df130f1f1a1ae6b7d3782c1b5208c13d6274977 (diff)
fix product variable in Export items
Consider a module M that's exported by Product B. Product A depends on product B and thus depends on M. This patch fixes the product variable in M that was referring to the exporting product B, not the importing product A. Task-number: QBS-729 Change-Id: Ia30b7159aa5d5ec37fe6257300e6c16205141f86 Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
Diffstat (limited to 'src/lib/corelib/language')
-rw-r--r--src/lib/corelib/language/evaluator.cpp5
-rw-r--r--src/lib/corelib/language/evaluator.h2
-rw-r--r--src/lib/corelib/language/evaluatorscriptclass.cpp21
-rw-r--r--src/lib/corelib/language/evaluatorscriptclass.h2
-rw-r--r--src/lib/corelib/language/projectresolver.cpp92
-rw-r--r--src/lib/corelib/language/projectresolver.h12
-rw-r--r--src/lib/corelib/language/tst_language.cpp1
7 files changed, 111 insertions, 24 deletions
diff --git a/src/lib/corelib/language/evaluator.cpp b/src/lib/corelib/language/evaluator.cpp
index d0c5dceb1..4c5494aa3 100644
--- a/src/lib/corelib/language/evaluator.cpp
+++ b/src/lib/corelib/language/evaluator.cpp
@@ -224,5 +224,10 @@ QScriptValue Evaluator::fileScope(const FileContextConstPtr &file)
return result;
}
+void Evaluator::setCachingEnabled(bool enabled)
+{
+ m_scriptClass->setValueCacheEnabled(enabled);
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h
index ec844af92..b1a598dce 100644
--- a/src/lib/corelib/language/evaluator.h
+++ b/src/lib/corelib/language/evaluator.h
@@ -66,6 +66,8 @@ public:
QScriptValue scriptValue(const Item *item);
QScriptValue fileScope(const FileContextConstPtr &file);
+ void setCachingEnabled(bool enabled);
+
private:
void onItemPropertyChanged(Item *item);
void onItemDestroyed(Item *item);
diff --git a/src/lib/corelib/language/evaluatorscriptclass.cpp b/src/lib/corelib/language/evaluatorscriptclass.cpp
index d523ef75c..2f9063e97 100644
--- a/src/lib/corelib/language/evaluatorscriptclass.cpp
+++ b/src/lib/corelib/language/evaluatorscriptclass.cpp
@@ -395,11 +395,14 @@ QScriptValue EvaluatorScriptClass::property(const QScriptValue &object, const QS
if (debugProperties)
m_logger.qbsTrace() << "[SC] property " << name;
- QScriptValue result = data->valueCache.value(name);
- if (result.isValid()) {
- if (debugProperties)
- m_logger.qbsTrace() << "[SC] cache hit " << name << ": " << resultToString(result);
- return result;
+ QScriptValue result;
+ if (m_valueCacheEnabled) {
+ result = data->valueCache.value(name);
+ if (result.isValid()) {
+ if (debugProperties)
+ m_logger.qbsTrace() << "[SC] cache hit " << name << ": " << resultToString(result);
+ return result;
+ }
}
SVConverter converter(this, &object, value, itemOfProperty);
@@ -413,10 +416,16 @@ QScriptValue EvaluatorScriptClass::property(const QScriptValue &object, const QS
if (debugProperties)
m_logger.qbsTrace() << "[SC] cache miss " << name << ": " << resultToString(result);
- data->valueCache.insert(name, result);
+ if (m_valueCacheEnabled)
+ data->valueCache.insert(name, result);
return result;
}
+void EvaluatorScriptClass::setValueCacheEnabled(bool enabled)
+{
+ m_valueCacheEnabled = enabled;
+}
+
QScriptValue EvaluatorScriptClass::scriptValueForBuiltin(BuiltinValue::Builtin builtin) const
{
switch (builtin) {
diff --git a/src/lib/corelib/language/evaluatorscriptclass.h b/src/lib/corelib/language/evaluatorscriptclass.h
index ba56f5d5e..f8b77f89b 100644
--- a/src/lib/corelib/language/evaluatorscriptclass.h
+++ b/src/lib/corelib/language/evaluatorscriptclass.h
@@ -57,6 +57,7 @@ public:
QScriptValue property(const QScriptValue &object,
const QScriptString &name, uint id);
+ void setValueCacheEnabled(bool enabled);
QScriptValue scriptValueForBuiltin(BuiltinValue::Builtin builtin) const;
private:
@@ -87,6 +88,7 @@ private:
};
QueryResult m_queryResult;
Logger m_logger;
+ bool m_valueCacheEnabled;
QScriptValue m_getNativeSettingBuiltin;
QScriptValue m_getEnvBuiltin;
QScriptValue m_getHostOSBuiltin;
diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp
index a353fa23a..ebd3a25db 100644
--- a/src/lib/corelib/language/projectresolver.cpp
+++ b/src/lib/corelib/language/projectresolver.cpp
@@ -859,7 +859,8 @@ void ProjectResolver::resolveExport(Item *item, ProjectContext *projectContext)
Q_UNUSED(projectContext);
checkCancelation();
const QString &productName = m_productContext->product->uniqueName();
- m_exports[productName] = evaluateModuleValues(item);
+ m_exports[productName] = item;
+ m_exportItemModules[item] = evaluateModuleValues(item, false);
}
static void insertExportedConfig(const QString &usedProductName,
@@ -891,6 +892,56 @@ static void addUsedProducts(ModuleLoaderResult::ProductInfo *productInfo,
*productsAdded = (oldCount != productInfo->usedProducts.count());
}
+typedef QHash<Item *, ValuePtr> ValuePerItem;
+
+static void replaceProductRecursive(Item *item, const ItemValuePtr &productItemValue,
+ ValuePerItem *seen)
+{
+ if (seen->contains(item))
+ return;
+ ValuePtr oldProductValue = item->property(QLatin1String("product"));
+ seen->insert(item, oldProductValue);
+ if (oldProductValue)
+ item->setProperty(QLatin1String("product"), productItemValue);
+ if (item->scope())
+ replaceProductRecursive(item->scope(), productItemValue, seen);
+ foreach (const Item::Module &module, item->modules())
+ replaceProductRecursive(module.item, productItemValue, seen);
+ foreach (Item *child, item->children())
+ replaceProductRecursive(child, productItemValue, seen);
+}
+
+static ValuePerItem replaceProduct(Item *item, const ItemValuePtr &productItemValue)
+{
+ ValuePerItem seen;
+ replaceProductRecursive(item, productItemValue, &seen);
+ return seen;
+}
+
+static void restoreOldProducts(const ValuePerItem &vip)
+{
+ for (ValuePerItem::const_iterator it = vip.constBegin(); it != vip.constEnd(); ++it) {
+ const ValuePtr &oldProductValue = it.value();
+ if (oldProductValue)
+ it.key()->setProperty(QLatin1String("product"), oldProductValue);
+ }
+}
+
+static void copyProperties(const QVariantMap &src, QVariantMap &dst)
+{
+ for (QVariantMap::const_iterator it = src.constBegin(); it != src.constEnd(); ++it) {
+ const QVariant &v = it.value();
+ if (v.type() == QVariant::Map) {
+ QVariant &dstValue = dst[it.key()];
+ QVariantMap dstMap = dstValue.toMap();
+ copyProperties(v.toMap(), dstMap);
+ dstValue = dstMap;
+ } else {
+ dst[it.key()] = v;
+ }
+ }
+}
+
void ProjectResolver::resolveProductDependencies(ProjectContext *projectContext)
{
// Collect product dependencies from Export items.
@@ -927,6 +978,7 @@ void ProjectResolver::resolveProductDependencies(ProjectContext *projectContext)
if (!rproduct->enabled)
continue;
Item *productItem = m_productItemMap.value(rproduct);
+ ItemValuePtr productItemValue = ItemValue::create(productItem);
foreach (const ModuleLoaderResult::ProductInfo::Dependency &dependency,
projectContext->loadResult->productInfos.value(productItem).usedProducts) {
const QString &usedProductName = dependency.uniqueName();
@@ -936,8 +988,22 @@ void ProjectResolver::resolveProductDependencies(ProjectContext *projectContext)
productItem->location());
rproduct->dependencies.insert(usedProduct);
+ // Evaluate properties of the Export item using the importing product.
+ Item *exportItem = m_exports.value(usedProductName);
+ ProductContext productContext;
+ productContext.product = usedProduct;
+ m_productContext = &productContext;
+ const ValuePerItem oldProducts = replaceProduct(exportItem, productItemValue);
+ m_evaluator->setCachingEnabled(false);
+ QVariantMap exportedConfig = evaluateModuleValues(exportItem);
+ m_evaluator->setCachingEnabled(true);
+ restoreOldProducts(oldProducts);
+
+ // Re-evaluate direct properties of the Export item using the exporting product.
+ copyProperties(m_exportItemModules.value(exportItem), exportedConfig);
+ m_productContext = 0;
+
// insert the configuration of the Export item into the product's configuration
- const QVariantMap exportedConfig = m_exports.value(usedProductName);
if (exportedConfig.isEmpty())
continue;
@@ -983,16 +1049,17 @@ void ProjectResolver::applyFileTaggers(const SourceArtifactPtr &artifact,
}
}
-QVariantMap ProjectResolver::evaluateModuleValues(Item *item) const
+QVariantMap ProjectResolver::evaluateModuleValues(Item *item, bool lookupPrototype) const
{
QVariantMap modules;
- evaluateModuleValues(item, &modules);
+ evaluateModuleValues(item, &modules, lookupPrototype);
QVariantMap result;
result[QLatin1String("modules")] = modules;
return result;
}
-void ProjectResolver::evaluateModuleValues(Item *item, QVariantMap *modulesMap) const
+void ProjectResolver::evaluateModuleValues(Item *item, QVariantMap *modulesMap,
+ bool lookupPrototype) const
{
checkCancelation();
for (Item::Modules::const_iterator it = item->modules().constBegin();
@@ -1000,22 +1067,23 @@ void ProjectResolver::evaluateModuleValues(Item *item, QVariantMap *modulesMap)
{
QVariantMap depmods;
const Item::Module &module = *it;
- evaluateModuleValues(module.item, &depmods);
- QVariantMap dep = evaluateProperties(module.item);
+ evaluateModuleValues(module.item, &depmods, lookupPrototype);
+ QVariantMap dep = evaluateProperties(module.item, lookupPrototype);
dep.insert(QLatin1String("modules"), depmods);
modulesMap->insert(ModuleLoader::fullModuleName(module.name), dep);
}
}
-QVariantMap ProjectResolver::evaluateProperties(Item *item) const
+QVariantMap ProjectResolver::evaluateProperties(Item *item, bool lookupPrototype) const
{
const QVariantMap tmplt;
- return evaluateProperties(item, item, tmplt);
+ return evaluateProperties(item, item, tmplt, lookupPrototype);
}
QVariantMap ProjectResolver::evaluateProperties(Item *item,
Item *propertiesContainer,
- const QVariantMap &tmplt) const
+ const QVariantMap &tmplt,
+ bool lookupPrototype) const
{
QVariantMap result = tmplt;
for (QMap<QString, ValuePtr>::const_iterator it = propertiesContainer->properties().begin();
@@ -1076,8 +1144,8 @@ QVariantMap ProjectResolver::evaluateProperties(Item *item,
break;
}
}
- return propertiesContainer->prototype()
- ? evaluateProperties(item, propertiesContainer->prototype(), result)
+ return lookupPrototype && propertiesContainer->prototype()
+ ? evaluateProperties(item, propertiesContainer->prototype(), result, true)
: result;
}
diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h
index 8fea4a1ff..05f326b2c 100644
--- a/src/lib/corelib/language/projectresolver.h
+++ b/src/lib/corelib/language/projectresolver.h
@@ -118,11 +118,12 @@ private:
void resolveProductDependencies(ProjectContext *projectContext);
void postProcess(const ResolvedProductPtr &product, ProjectContext *projectContext) const;
void applyFileTaggers(const ResolvedProductPtr &product) const;
- QVariantMap evaluateModuleValues(Item *item) const;
- void evaluateModuleValues(Item *item, QVariantMap *modulesMap) const;
- QVariantMap evaluateProperties(Item *item) const;
+ QVariantMap evaluateModuleValues(Item *item, bool lookupPrototype = true) const;
+ void evaluateModuleValues(Item *item, QVariantMap *modulesMap,
+ bool lookupPrototype = true) const;
+ QVariantMap evaluateProperties(Item *item, bool lookupPrototype = true) const;
QVariantMap evaluateProperties(Item *item, Item *propertiesContainer,
- const QVariantMap &tmplt) const;
+ const QVariantMap &tmplt, bool lookupPrototype = true) const;
QVariantMap createProductConfig() const;
QString convertPathProperty(const QString &path, const QString &dirPath) const;
QStringList convertPathListProperty(const QStringList &paths, const QString &dirPath) const;
@@ -138,7 +139,8 @@ private:
QMap<QString, ResolvedProductPtr> m_productsByName;
QHash<ResolvedProductPtr, Item *> m_productItemMap;
mutable QHash<FileContextConstPtr, ResolvedFileContextPtr> m_fileContextMap;
- QMap<QString, QVariantMap> m_exports;
+ QMap<QString, Item *> m_exports;
+ QHash<Item *, QVariantMap> m_exportItemModules; // ### merge with ExportContext in 1.4.
SetupProjectParameters m_setupParams;
typedef void (ProjectResolver::*ItemFuncPtr)(Item *item, ProjectContext *projectContext);
diff --git a/src/lib/corelib/language/tst_language.cpp b/src/lib/corelib/language/tst_language.cpp
index 3857e48e6..c38fa5876 100644
--- a/src/lib/corelib/language/tst_language.cpp
+++ b/src/lib/corelib/language/tst_language.cpp
@@ -420,7 +420,6 @@ void TestLanguage::exports()
QVariant propertyValue = getConfigProperty(product->moduleProperties->value(), propertyName);
QCOMPARE(propertyValue.toStringList(), QStringList() << "USE_MYLIB");
- QEXPECT_FAIL(0, "QBS-729", Continue);
QCOMPARE(PropertyFinder().propertyValue(product->moduleProperties->value(), "dummy",
"productName").toString(), QString("myapp"));