aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/language
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@theqtcompany.com>2015-02-12 18:33:53 +0100
committerChristian Kandeler <christian.kandeler@theqtcompany.com>2015-02-13 14:33:12 +0000
commitf53d724eec925180e94cda4bd7db6b86eba0f82b (patch)
treec62fd0841a6563f89cc19dee7b40bc3a2344bd51 /src/lib/corelib/language
parent04df1532c412cb62db033865055d14dfe3ec7b71 (diff)
Don't evaluate properties that will never be seen.
During project resolving, we can make use of our knowledge of how the PropertyFinder works, skipping evaluation for "shadowed" properties. In the long term, we might want to get rid of the nested modules map altogether and replace it with a "flat" map (with special support for mergeable list values). Task-number: QBS-746 Change-Id: I75f62239daadce1f8826444a2e3b3a51d581df98 Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
Diffstat (limited to 'src/lib/corelib/language')
-rw-r--r--src/lib/corelib/language/projectresolver.cpp101
-rw-r--r--src/lib/corelib/language/projectresolver.h22
2 files changed, 88 insertions, 35 deletions
diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp
index 3117edd80..cffe6b074 100644
--- a/src/lib/corelib/language/projectresolver.cpp
+++ b/src/lib/corelib/language/projectresolver.cpp
@@ -1070,13 +1070,24 @@ void ProjectResolver::applyFileTaggers(const SourceArtifactPtr &artifact,
}
}
-QVariantMap ProjectResolver::evaluateModuleValues(Item *item, bool lookupPrototype) const
+struct ModuleInfo {
+ QString fullName;
+ QVariantMap propertyMap;
+ QStringList ownProperties;
+};
+
+static void gatherModuleValues(Item *item, QVariantMap *parentModulesMap,
+ const QHash<Item *, ModuleInfo> &moduleInfo)
{
- QVariantMap modules;
- evaluateModuleValues(item, &modules, lookupPrototype);
- QVariantMap result;
- result[QLatin1String("modules")] = modules;
- return result;
+ foreach (const Item::Module &module, item->modules()) {
+ const ModuleInfo &mi = moduleInfo.value(module.item);
+ QVariantMap modulesMap;
+ gatherModuleValues(module.item, &modulesMap, moduleInfo);
+ QVariantMap propertyMap = mi.propertyMap;
+ propertyMap.insert(QLatin1String("modules"), modulesMap);
+ parentModulesMap->insert(mi.fullName, propertyMap);
+ parentModulesMap->insert(QLatin1Char('@') + mi.fullName, mi.ownProperties);
+ }
}
static QStringList ownPropertiesSet(Item *item)
@@ -1094,46 +1105,53 @@ static QStringList ownPropertiesSet(Item *item)
return names;
}
-void ProjectResolver::evaluateModuleValues(Item *item, QVariantMap *modulesMap,
- bool lookupPrototype) const
+QVariantMap ProjectResolver::evaluateModuleValues(Item *item, bool lookupPrototype) const
{
- checkCancelation();
- QSet<QStringList> seenModuleNames;
+ QHash<Item *, ModuleInfo> moduleInfo;
+ QHash<QString, EvalResult> globalResult;
- for (Item::Modules::const_iterator it = item->modules().constBegin();
- it != item->modules().constEnd(); ++it)
- {
- const Item::Module &module = *it;
- if (seenModuleNames.contains(module.name))
- continue;
- seenModuleNames << module.name;
-
- QVariantMap depmods;
- evaluateModuleValues(module.item, &depmods, lookupPrototype);
- QVariantMap dep = evaluateProperties(module.item, lookupPrototype);
- dep.insert(QLatin1String("modules"), depmods);
+ // Optimization in evaluateProperties() requires breadth-first traversal.
+ QList<Item::Module> modulesQueue = item->modules();
+ while (!modulesQueue.isEmpty()) {
+ checkCancelation();
+ const Item::Module module = modulesQueue.takeFirst();
const QString fullName = ModuleLoader::fullModuleName(module.name);
- modulesMap->insert(fullName, dep);
- modulesMap->insert(QLatin1Char('@') + fullName, ownPropertiesSet(module.item));
+ ModulePropertyEvalContext evalContext;
+ evalContext.globalResult = &globalResult;
+ evalContext.moduleName = fullName;
+ evalContext.ownProperties = ownPropertiesSet(module.item);
+ ModuleInfo mi;
+ mi.fullName = fullName;
+ mi.propertyMap = evaluateProperties(module.item, evalContext, lookupPrototype);
+ mi.ownProperties = evalContext.ownProperties;
+ moduleInfo.insert(module.item, mi);
+ modulesQueue << module.item->modules();
}
+
+ QVariantMap modules;
+ gatherModuleValues(item, &modules, moduleInfo);
+ QVariantMap result;
+ result[QLatin1String("modules")] = modules;
+ return result;
}
-QVariantMap ProjectResolver::evaluateProperties(Item *item, bool lookupPrototype) const
+QVariantMap ProjectResolver::evaluateProperties(Item *item,
+ const ModulePropertyEvalContext &evalContext, bool lookupPrototype) const
{
const QVariantMap tmplt;
- return evaluateProperties(item, item, tmplt, lookupPrototype);
+ return evaluateProperties(item, item, evalContext, tmplt, lookupPrototype);
}
QVariantMap ProjectResolver::evaluateProperties(Item *item,
- Item *propertiesContainer,
- const QVariantMap &tmplt,
- bool lookupPrototype) const
+ Item *propertiesContainer, const ModulePropertyEvalContext &evalContext,
+ const QVariantMap &tmplt, bool lookupPrototype) const
{
QVariantMap result = tmplt;
for (QMap<QString, ValuePtr>::const_iterator it = propertiesContainer->properties().begin();
it != propertiesContainer->properties().end(); ++it)
{
checkCancelation();
+ const QString fullKey = evalContext.moduleName + QLatin1Char('.') + it.key();
switch (it.value()->type()) {
case Value::ItemValueType:
{
@@ -1157,6 +1175,22 @@ QVariantMap ProjectResolver::evaluateProperties(Item *item,
break;
}
+ // Skip values that the PropertyFinder will never see due to them being shadowed
+ // by values in other, higher-precedence instances of the module.
+ const bool isPotentialGlobalEntry = evalContext.globalResult
+ && pd.type() != PropertyDeclaration::StringList
+ && pd.type() != PropertyDeclaration::PathList;
+ const bool isOwnProperty = std::binary_search(evalContext.ownProperties.constBegin(),
+ evalContext.ownProperties.constEnd(), it.key());
+ if (isPotentialGlobalEntry) {
+ const QHash<QString, EvalResult>::ConstIterator it
+ = evalContext.globalResult->find(fullKey);
+ if (it != evalContext.globalResult->constEnd()) {
+ if (!isOwnProperty || it->strongPrecedence)
+ break;
+ }
+ }
+
bool cacheDisabled = false;
const JSSourceValuePtr srcValue = it.value().staticCast<JSSourceValue>();
if (m_disableCachedEvaluation && (pd.type() == PropertyDeclaration::Path
@@ -1187,6 +1221,8 @@ QVariantMap ProjectResolver::evaluateProperties(Item *item,
else if (pd.type() == PropertyDeclaration::StringList)
v = v.toStringList();
result[it.key()] = v;
+ if (isPotentialGlobalEntry)
+ evalContext.globalResult->insert(fullKey, EvalResult(v, isOwnProperty));
break;
}
case Value::VariantValueType:
@@ -1195,6 +1231,8 @@ QVariantMap ProjectResolver::evaluateProperties(Item *item,
break;
VariantValuePtr vvp = it.value().staticCast<VariantValue>();
result[it.key()] = vvp->value();
+ if (evalContext.globalResult)
+ evalContext.globalResult->insert(fullKey, EvalResult(vvp->value(), true));
break;
}
case Value::BuiltinValueType:
@@ -1203,14 +1241,15 @@ QVariantMap ProjectResolver::evaluateProperties(Item *item,
}
}
return lookupPrototype && propertiesContainer->prototype()
- ? evaluateProperties(item, propertiesContainer->prototype(), result, true)
+ ? evaluateProperties(item, propertiesContainer->prototype(), evalContext, result, true)
: result;
}
QVariantMap ProjectResolver::createProductConfig() const
{
QVariantMap cfg = evaluateModuleValues(m_productContext->item);
- cfg = evaluateProperties(m_productContext->item, m_productContext->item, cfg);
+ cfg = evaluateProperties(m_productContext->item, m_productContext->item,
+ ModulePropertyEvalContext(), cfg);
return cfg;
}
diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h
index 85edf1d07..5bbe9a631 100644
--- a/src/lib/corelib/language/projectresolver.h
+++ b/src/lib/corelib/language/projectresolver.h
@@ -120,11 +120,25 @@ private:
void postProcess(const ResolvedProductPtr &product, ProjectContext *projectContext) const;
void applyFileTaggers(const ResolvedProductPtr &product) 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;
+
+ struct EvalResult {
+ EvalResult(const QVariant &v, bool s) : value(v), strongPrecedence(s) {}
+ EvalResult() : strongPrecedence(false) {}
+ QVariant value;
+ bool strongPrecedence;
+ };
+
+ struct ModulePropertyEvalContext {
+ ModulePropertyEvalContext() : globalResult(0) {}
+ QString moduleName;
+ QHash<QString, EvalResult> *globalResult;
+ QStringList ownProperties;
+ };
+ QVariantMap evaluateProperties(Item *item, const ModulePropertyEvalContext &evalContext,
+ bool lookupPrototype = true) const;
QVariantMap evaluateProperties(Item *item, Item *propertiesContainer,
- const QVariantMap &tmplt, bool lookupPrototype = true) const;
+ const ModulePropertyEvalContext &evalContext, 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;