aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/language
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/corelib/language')
-rw-r--r--src/lib/corelib/language/artifactproperties.cpp5
-rw-r--r--src/lib/corelib/language/asttools.cpp4
-rw-r--r--src/lib/corelib/language/builtindeclarations.cpp2
-rw-r--r--src/lib/corelib/language/builtindeclarations.h2
-rw-r--r--src/lib/corelib/language/deprecationinfo.h6
-rw-r--r--src/lib/corelib/language/evaluator.h2
-rw-r--r--src/lib/corelib/language/identifiersearch.cpp4
-rw-r--r--src/lib/corelib/language/item.cpp14
-rw-r--r--src/lib/corelib/language/itempool.cpp4
-rw-r--r--src/lib/corelib/language/itemreadervisitorstate.cpp5
-rw-r--r--src/lib/corelib/language/language.cpp35
-rw-r--r--src/lib/corelib/language/language.h26
-rw-r--r--src/lib/corelib/language/moduleloader.cpp349
-rw-r--r--src/lib/corelib/language/moduleloader.h18
-rw-r--r--src/lib/corelib/language/modulemerger.cpp226
-rw-r--r--src/lib/corelib/language/modulemerger.h31
-rw-r--r--src/lib/corelib/language/moduleproviderinfo.h9
-rw-r--r--src/lib/corelib/language/projectresolver.cpp11
-rw-r--r--src/lib/corelib/language/projectresolver.h6
-rw-r--r--src/lib/corelib/language/property.h10
-rw-r--r--src/lib/corelib/language/propertydeclaration.cpp15
-rw-r--r--src/lib/corelib/language/propertymapinternal.cpp8
-rw-r--r--src/lib/corelib/language/qualifiedid.cpp4
-rw-r--r--src/lib/corelib/language/resolvedfilecontext.h2
-rw-r--r--src/lib/corelib/language/scriptengine.cpp13
-rw-r--r--src/lib/corelib/language/value.cpp10
-rw-r--r--src/lib/corelib/language/value.h8
27 files changed, 445 insertions, 384 deletions
diff --git a/src/lib/corelib/language/artifactproperties.cpp b/src/lib/corelib/language/artifactproperties.cpp
index dd61bf1a2..011e58d88 100644
--- a/src/lib/corelib/language/artifactproperties.cpp
+++ b/src/lib/corelib/language/artifactproperties.cpp
@@ -48,9 +48,7 @@ ArtifactPropertiesPtr ArtifactProperties::create()
return ArtifactPropertiesPtr(new ArtifactProperties);
}
-ArtifactProperties::ArtifactProperties()
-{
-}
+ArtifactProperties::ArtifactProperties() = default;
FileTags ArtifactProperties::extraFileTags() const
{
@@ -66,6 +64,7 @@ bool operator==(const ArtifactProperties &ap1, const ArtifactProperties &ap2)
{
return ap1.fileTagsFilter() == ap2.fileTagsFilter()
&& ap1.extraFileTags() == ap2.extraFileTags()
+ && !ap1.propertyMap() == !ap2.propertyMap()
&& *ap1.propertyMap() == *ap2.propertyMap();
}
diff --git a/src/lib/corelib/language/asttools.cpp b/src/lib/corelib/language/asttools.cpp
index 617c8b95b..1b6abac7f 100644
--- a/src/lib/corelib/language/asttools.cpp
+++ b/src/lib/corelib/language/asttools.cpp
@@ -61,13 +61,13 @@ QString textOf(const QString &source, QbsQmlJS::AST::Node *node)
if (!node)
return {};
return source.mid(node->firstSourceLocation().begin(),
- node->lastSourceLocation().end() - node->firstSourceLocation().begin());
+ int(node->lastSourceLocation().end() - node->firstSourceLocation().begin()));
}
QStringRef textRefOf(const QString &source, QbsQmlJS::AST::Node *node)
{
const quint32 firstBegin = node->firstSourceLocation().begin();
- return source.midRef(firstBegin, node->lastSourceLocation().end() - firstBegin);
+ return source.midRef(firstBegin, int(node->lastSourceLocation().end() - firstBegin));
}
} // namespace Internal
diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp
index 68355df51..13783d3b9 100644
--- a/src/lib/corelib/language/builtindeclarations.cpp
+++ b/src/lib/corelib/language/builtindeclarations.cpp
@@ -125,7 +125,7 @@ ItemDeclaration BuiltinDeclarations::declarationsForType(ItemType type) const
}
ItemType BuiltinDeclarations::typeForName(const QString &typeName,
- const CodeLocation location) const
+ const CodeLocation &location) const
{
const auto it = m_typeMap.constFind(typeName);
if (it == m_typeMap.constEnd())
diff --git a/src/lib/corelib/language/builtindeclarations.h b/src/lib/corelib/language/builtindeclarations.h
index 988f9ab81..9d7aee982 100644
--- a/src/lib/corelib/language/builtindeclarations.h
+++ b/src/lib/corelib/language/builtindeclarations.h
@@ -62,7 +62,7 @@ public:
QStringList allTypeNames() const;
ItemDeclaration declarationsForType(ItemType type) const;
ItemType typeForName(const QString &typeName,
- const CodeLocation location = CodeLocation()) const;
+ const CodeLocation &location = CodeLocation()) const;
QString nameForType(ItemType itemType) const;
QStringList argumentNamesForScriptFunction(ItemType itemType, const QString &scriptName) const;
diff --git a/src/lib/corelib/language/deprecationinfo.h b/src/lib/corelib/language/deprecationinfo.h
index 502715b84..89cd07f4a 100644
--- a/src/lib/corelib/language/deprecationinfo.h
+++ b/src/lib/corelib/language/deprecationinfo.h
@@ -50,11 +50,11 @@ class DeprecationInfo
{
public:
explicit DeprecationInfo(const Version &removalVersion,
- const QString &additionalUserInfo = QString())
+ QString additionalUserInfo = QString())
: m_removalVersion(removalVersion)
- , m_additionalUserInfo(additionalUserInfo)
+ , m_additionalUserInfo(std::move(additionalUserInfo))
{}
- DeprecationInfo() {}
+ DeprecationInfo() = default;
bool isValid() const { return m_removalVersion.isValid(); }
Version removalVersion() const { return m_removalVersion; }
diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h
index d8931a37e..f8535d0d7 100644
--- a/src/lib/corelib/language/evaluator.h
+++ b/src/lib/corelib/language/evaluator.h
@@ -64,7 +64,7 @@ class QBS_AUTOTEST_EXPORT Evaluator : private ItemObserver
public:
Evaluator(ScriptEngine *scriptEngine);
- virtual ~Evaluator();
+ ~Evaluator() override;
ScriptEngine *engine() const { return m_scriptEngine; }
QScriptValue property(const Item *item, const QString &name);
diff --git a/src/lib/corelib/language/identifiersearch.cpp b/src/lib/corelib/language/identifiersearch.cpp
index 973aae6a8..49ceab36c 100644
--- a/src/lib/corelib/language/identifiersearch.cpp
+++ b/src/lib/corelib/language/identifiersearch.cpp
@@ -43,9 +43,7 @@
namespace qbs {
namespace Internal {
-IdentifierSearch::IdentifierSearch()
-{
-}
+IdentifierSearch::IdentifierSearch() = default;
void IdentifierSearch::start(QbsQmlJS::AST::Node *node)
{
diff --git a/src/lib/corelib/language/item.cpp b/src/lib/corelib/language/item.cpp
index 9f754bdd7..a86cfeac1 100644
--- a/src/lib/corelib/language/item.cpp
+++ b/src/lib/corelib/language/item.cpp
@@ -203,15 +203,15 @@ bool Item::isOfTypeOrhasParentOfType(ItemType type) const
PropertyDeclaration Item::propertyDeclaration(const QString &name, bool allowExpired) const
{
- PropertyDeclaration decl = m_propertyDeclarations.value(name);
- if (decl.isValid())
- return decl;
+ auto it = m_propertyDeclarations.find(name);
+ if (it != m_propertyDeclarations.end())
+ return it.value();
if (allowExpired) {
- decl = m_expiredPropertyDeclarations.value(name);
- if (decl.isValid())
- return decl;
+ it = m_expiredPropertyDeclarations.find(name);
+ if (it != m_expiredPropertyDeclarations.end())
+ return it.value();
}
- return m_prototype ? m_prototype->propertyDeclaration(name) : decl;
+ return m_prototype ? m_prototype->propertyDeclaration(name) : PropertyDeclaration();
}
void Item::addModule(const Item::Module &module)
diff --git a/src/lib/corelib/language/itempool.cpp b/src/lib/corelib/language/itempool.cpp
index 3da8b947b..ccd22fe2e 100644
--- a/src/lib/corelib/language/itempool.cpp
+++ b/src/lib/corelib/language/itempool.cpp
@@ -43,9 +43,7 @@
namespace qbs {
namespace Internal {
-ItemPool::ItemPool()
-{
-}
+ItemPool::ItemPool() = default;
ItemPool::~ItemPool()
{
diff --git a/src/lib/corelib/language/itemreadervisitorstate.cpp b/src/lib/corelib/language/itemreadervisitorstate.cpp
index ca6ba2e12..20ddb5cfb 100644
--- a/src/lib/corelib/language/itemreadervisitorstate.cpp
+++ b/src/lib/corelib/language/itemreadervisitorstate.cpp
@@ -81,10 +81,7 @@ public:
{
}
- ASTCacheValue(const ASTCacheValue &other)
- : d(other.d)
- {
- }
+ ASTCacheValue(const ASTCacheValue &other) = default;
void setProcessingFlag(bool b) { d->processing = b; }
bool isProcessing() const { return d->processing; }
diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp
index 40549b836..3b3e7401e 100644
--- a/src/lib/corelib/language/language.cpp
+++ b/src/lib/corelib/language/language.cpp
@@ -188,15 +188,9 @@ void ResolvedGroup::store(PersistentPool &pool)
* \sa Rule
*/
-ScriptFunction::ScriptFunction()
-{
-
-}
-
-ScriptFunction::~ScriptFunction()
-{
+ScriptFunction::ScriptFunction() = default;
-}
+ScriptFunction::~ScriptFunction() = default;
/*!
* \variable ScriptFunction::script
@@ -282,7 +276,7 @@ QString Rule::toString() const
FileTags Rule::staticOutputFileTags() const
{
FileTags result;
- for (const RuleArtifactConstPtr &artifact : artifacts)
+ for (const auto &artifact : artifacts)
result.unite(artifact->fileTags);
return result;
}
@@ -312,9 +306,7 @@ ResolvedProduct::ResolvedProduct()
{
}
-ResolvedProduct::~ResolvedProduct()
-{
-}
+ResolvedProduct::~ResolvedProduct() = default;
void ResolvedProduct::accept(BuildGraphVisitor *visitor) const
{
@@ -331,7 +323,7 @@ void ResolvedProduct::accept(BuildGraphVisitor *visitor) const
std::vector<SourceArtifactPtr> ResolvedProduct::allFiles() const
{
std::vector<SourceArtifactPtr> lst;
- for (const GroupConstPtr &group : groups)
+ for (const auto &group : groups)
lst << group->allFiles();
return lst;
}
@@ -343,7 +335,7 @@ std::vector<SourceArtifactPtr> ResolvedProduct::allFiles() const
std::vector<SourceArtifactPtr> ResolvedProduct::allEnabledFiles() const
{
std::vector<SourceArtifactPtr> lst;
- for (const GroupConstPtr &group : groups) {
+ for (const auto &group : groups) {
if (group->enabled)
lst << group->allFiles();
}
@@ -364,7 +356,7 @@ FileTags ResolvedProduct::fileTagsForFileName(const QString &fileName) const
return result;
}
} else {
- priority.reset(new int(tagger->priority()));
+ priority = std::make_unique<int>(tagger->priority());
}
result.unite(tagger->fileTags());
break;
@@ -524,9 +516,7 @@ ResolvedProject::ResolvedProject() : enabled(true), m_topLevelProject(nullptr)
{
}
-ResolvedProject::~ResolvedProject()
-{
-}
+ResolvedProject::~ResolvedProject() = default;
void ResolvedProject::accept(BuildGraphVisitor *visitor) const
{
@@ -551,7 +541,7 @@ TopLevelProject *ResolvedProject::topLevelProject()
std::vector<ResolvedProjectPtr> ResolvedProject::allSubProjects() const
{
std::vector<ResolvedProjectPtr> projectList = subProjects;
- for (const ResolvedProjectConstPtr &subProject : subProjects)
+ for (const auto &subProject : subProjects)
projectList << subProject->allSubProjects();
return projectList;
}
@@ -559,7 +549,7 @@ std::vector<ResolvedProjectPtr> ResolvedProject::allSubProjects() const
std::vector<ResolvedProductPtr> ResolvedProject::allProducts() const
{
std::vector<ResolvedProductPtr> productList = products;
- for (const ResolvedProjectConstPtr &subProject : qAsConst(subProjects))
+ for (const auto &subProject : qAsConst(subProjects))
productList << subProject->allProducts();
return productList;
}
@@ -765,7 +755,7 @@ void SourceWildCards::expandPatterns(Set<QString> &result, const GroupConstPtr &
if (baseDir.startsWith(buildDir))
return;
- dirTimeStamps.push_back({ baseDir, FileInfo(baseDir).lastModified() });
+ dirTimeStamps.emplace_back(baseDir, FileInfo(baseDir).lastModified());
QStringList changed_parts = parts;
bool recursive = false;
@@ -810,7 +800,7 @@ void SourceWildCards::expandPatterns(Set<QString> &result, const GroupConstPtr &
expandPatterns(result, group, changed_parts, filePath, buildDir);
} else {
if (parentDir != baseDir)
- dirTimeStamps.push_back({parentDir, FileInfo(baseDir).lastModified()});
+ dirTimeStamps.emplace_back(parentDir, FileInfo(baseDir).lastModified());
result += QDir::cleanPath(filePath);
}
}
@@ -867,6 +857,7 @@ bool operator==(const SourceArtifactInternal &sa1, const SourceArtifactInternal
&& sa1.fileTags == sa2.fileTags
&& sa1.overrideFileTags == sa2.overrideFileTags
&& sa1.targetOfModule == sa2.targetOfModule
+ && !sa1.properties == !sa2.properties
&& *sa1.properties == *sa2.properties;
}
diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h
index 65879dd56..bbd851333 100644
--- a/src/lib/corelib/language/language.h
+++ b/src/lib/corelib/language/language.h
@@ -99,7 +99,7 @@ public:
private:
FileTagger(const QStringList &patterns, FileTags fileTags, int priority);
- FileTagger() {}
+ FileTagger() = default;
void setPatterns(const QStringList &patterns);
@@ -139,20 +139,20 @@ public:
}
private:
- Probe() {}
- Probe(const QString &globalId,
+ Probe() = default;
+ Probe(QString globalId,
const CodeLocation &location,
bool condition,
- const QString &configureScript,
- const QVariantMap &properties,
- const QVariantMap &initialProperties,
- const std::vector<QString> &importedFilesUsed)
- : m_globalId(globalId)
+ QString configureScript,
+ QVariantMap properties,
+ QVariantMap initialProperties,
+ std::vector<QString> importedFilesUsed)
+ : m_globalId(std::move(globalId))
, m_location(location)
- , m_configureScript(configureScript)
- , m_properties(properties)
- , m_initialProperties(initialProperties)
- , m_importedFilesUsed(importedFilesUsed)
+ , m_configureScript(std::move(configureScript))
+ , m_properties(std::move(properties))
+ , m_initialProperties(std::move(initialProperties))
+ , m_importedFilesUsed(std::move(importedFilesUsed))
, m_condition(condition)
{}
@@ -378,7 +378,7 @@ public:
}
private:
- ResolvedModule() {}
+ ResolvedModule() = default;
};
bool operator==(const ResolvedModule &m1, const ResolvedModule &m2);
inline bool operator!=(const ResolvedModule &m1, const ResolvedModule &m2) { return !(m1 == m2); }
diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp
index 9c8f9da1d..56fbc198e 100644
--- a/src/lib/corelib/language/moduleloader.cpp
+++ b/src/lib/corelib/language/moduleloader.cpp
@@ -71,20 +71,24 @@
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
+#include <QtCore/qglobalstatic.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qtemporaryfile.h>
#include <QtCore/qtextstream.h>
+#include <QtCore/qthreadstorage.h>
#include <QtScript/qscriptvalueiterator.h>
#include <algorithm>
+#include <memory>
#include <utility>
namespace qbs {
namespace Internal {
-static QString shadowProductPrefix() { return QStringLiteral("__shadow__"); }
+using MultiplexConfigurationByIdTable = QThreadStorage<QHash<QString, QVariantMap> >;
+Q_GLOBAL_STATIC(MultiplexConfigurationByIdTable, multiplexConfigurationsById);
static void handlePropertyError(const ErrorInfo &error, const SetupProjectParameters &params,
Logger &logger)
@@ -94,6 +98,20 @@ static void handlePropertyError(const ErrorInfo &error, const SetupProjectParame
logger.printWarning(error);
}
+static bool multiplexConfigurationIntersects(const QVariantMap &lhs, const QVariantMap &rhs)
+{
+ QBS_CHECK(!lhs.isEmpty() && !rhs.isEmpty());
+
+ for (auto lhsProperty = lhs.constBegin(); lhsProperty != lhs.constEnd(); lhsProperty++) {
+ const auto rhsProperty = rhs.find(lhsProperty.key());
+ const bool isCommonProperty = rhsProperty != rhs.constEnd();
+ if (isCommonProperty && lhsProperty.value() != rhsProperty.value())
+ return false;
+ }
+
+ return true;
+}
+
class ModuleLoader::ItemModuleList : public QList<Item::Module> {};
static QString probeGlobalId(Item *probe)
@@ -292,7 +310,7 @@ ModuleLoaderResult ModuleLoader::load(const SetupProjectParameters &parameters)
= m_elapsedTimePropertyChecking = 0;
m_elapsedTimeProbes = 0;
m_probesEncountered = m_probesRun = m_probesCachedCurrent = m_probesCachedOld = 0;
- m_settings.reset(new Settings(parameters.settingsDirectory()));
+ m_settings = std::make_unique<Settings>(parameters.settingsDirectory());
const auto keys = m_parameters.overriddenValues().keys();
for (const QString &key : keys) {
@@ -381,9 +399,9 @@ class PropertyDeclarationCheck : public ValueHandler
Logger &m_logger;
public:
PropertyDeclarationCheck(const Set<Item *> &disabledItems,
- const SetupProjectParameters &params, Logger &logger)
+ SetupProjectParameters params, Logger &logger)
: m_disabledItems(disabledItems)
- , m_params(params)
+ , m_params(std::move(params))
, m_logger(logger)
{
}
@@ -616,7 +634,7 @@ void ModuleLoader::handleTopLevelProject(ModuleLoaderResult *loadResult, Item *p
for (ProductContext * const p : productSorter.sortedProducts()) {
try {
handleProduct(p);
- if (p->name.startsWith(shadowProductPrefix()))
+ if (p->name.startsWith(StringConstants::shadowProductPrefix()))
tlp.probes << p->info.probes;
} catch (const ErrorInfo &err) {
handleProductError(err, p);
@@ -688,6 +706,9 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult,
m_qbsVersion.toString()));
}
+ for (Item * const child : projectItem->children())
+ child->setScope(projectContext.scope);
+
resolveProbes(&dummyProductContext, projectItem);
projectContext.topLevelProject->probes << dummyProductContext.info.probes;
@@ -695,7 +716,6 @@ void ModuleLoader::handleProject(ModuleLoaderResult *loadResult,
QList<Item *> multiplexedProducts;
for (Item * const child : projectItem->children()) {
- child->setScope(projectContext.scope);
if (child->type() == ItemType::Product)
multiplexedProducts << multiplexProductItem(&dummyProductContext, child);
}
@@ -762,9 +782,24 @@ QString ModuleLoader::MultiplexInfo::toIdString(size_t row) const
const VariantValuePtr &mpvalue = mprow.at(column);
multiplexConfiguration.insert(propertyName, mpvalue->value());
}
- return QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration)
- .toJson(QJsonDocument::Compact)
- .toBase64());
+ QString id = QString::fromUtf8(QJsonDocument::fromVariant(multiplexConfiguration)
+ .toJson(QJsonDocument::Compact)
+ .toBase64());
+ // Cache for later use in:multiplexIdToVariantMap()
+ multiplexConfigurationsById->localData().insert(id, multiplexConfiguration);
+ return id;
+}
+
+QVariantMap ModuleLoader::MultiplexInfo::multiplexIdToVariantMap(const QString &multiplexId)
+{
+ if (multiplexId.isEmpty())
+ return QVariantMap();
+
+ QVariantMap result = multiplexConfigurationsById->localData().value(multiplexId);
+ // We assume that MultiplexInfo::toIdString() has been called for this
+ // particular multiplex configuration.
+ QBS_CHECK(!result.isEmpty());
+ return result;
}
void qbs::Internal::ModuleLoader::ModuleLoader::dump(const ModuleLoader::MultiplexInfo &mpi)
@@ -1085,66 +1120,111 @@ void ModuleLoader::adjustDependenciesForMultiplexing(const ProductContext &produ
StringConstants::profilesProperty(), &profilesPropertyIsSet);
const auto productRange = m_productsByName.equal_range(name);
- std::vector<const ProductContext *> dependencies;
+ if (productRange.first == productRange.second) {
+ // Dependency is a module. Nothing to adjust.
+ return;
+ }
+
+ std::vector<const ProductContext *> multiplexedDependencies;
bool hasNonMultiplexedDependency = false;
for (auto it = productRange.first; it != productRange.second; ++it) {
- if (!it->second->multiplexConfigurationId.isEmpty()) {
- dependencies.push_back(it->second);
- if (productIsMultiplexed && !profilesPropertyIsSet)
- break;
- } else {
+ if (!it->second->multiplexConfigurationId.isEmpty())
+ multiplexedDependencies.push_back(it->second);
+ else
hasNonMultiplexedDependency = true;
- break;
- }
}
+ bool hasMultiplexedDependencies = !multiplexedDependencies.empty();
// These are the allowed cases:
// (1) Normal dependency with no multiplexing whatsoever.
// (2) Both product and dependency are multiplexed.
+ // (2a) The profiles property is not set, we want to depend on the best
+ // matching variant.
+ // (2b) The profiles property is set, we want to depend on all variants
+ // with a matching profile.
// (3) The product is not multiplexed, but the dependency is.
- // (3a) The dependency has an aggregator. We want to depend on the aggregator.
- // (3b) The dependency does not have an aggregator. We want to depend on all the
- // multiplexed variants.
- // (4) The product is multiplexed, but the dependency is not. This case is implicitly
- // handled, because we don't have to adapt any Depends items.
+ // (3a) The profiles property is not set, the dependency has an aggregator.
+ // We want to depend on the aggregator.
+ // (3b) The profiles property is not set, the dependency does not have an
+ // aggregator. We want to depend on all the multiplexed variants.
+ // (3c) The profiles property is set, we want to depend on all variants
+ // with a matching profile regardless of whether an aggregator exists or not.
+ // (4) The product is multiplexed, but the dependency is not. We don't have to adapt
+ // any Depends items.
// (5) The product is a "shadow product". In that case, we know which product
// it should have a dependency on, and we make sure we depend on that.
- // (1) and (3a)
- if (!productIsMultiplexed && hasNonMultiplexedDependency)
+ // (1) and (4)
+ if (!hasMultiplexedDependencies)
+ return;
+
+ // (3a)
+ if (!productIsMultiplexed && hasNonMultiplexedDependency && !profilesPropertyIsSet)
return;
QStringList multiplexIds;
const ShadowProductInfo shadowProductInfo = getShadowProductInfo(product);
const bool isShadowProduct = shadowProductInfo.first && shadowProductInfo.second == name;
- for (const ProductContext *dependency : dependencies) {
+ const auto productMultiplexConfig =
+ MultiplexInfo::multiplexIdToVariantMap(product.multiplexConfigurationId);
+
+ for (const ProductContext *dependency : multiplexedDependencies) {
const bool depMatchesShadowProduct = isShadowProduct
&& dependency->item == product.item->parent();
const QString depMultiplexId = dependency->multiplexConfigurationId;
if (depMatchesShadowProduct) { // (5)
dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
VariantValue::create(depMultiplexId));
- multiplexIds.clear();
- break;
- }
- if (productIsMultiplexed && !profilesPropertyIsSet) { // (2)
- const ValuePtr &multiplexId = product.item->property(
- StringConstants::multiplexConfigurationIdProperty());
- dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
- multiplexId);
- break;
+ return;
}
+ if (productIsMultiplexed && !profilesPropertyIsSet) { // 2a
+ if (dependency->multiplexConfigurationId == product.multiplexConfigurationId) {
+ const ValuePtr &multiplexId = product.item->property(
+ StringConstants::multiplexConfigurationIdProperty());
+ dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
+ multiplexId);
+ return;
- // (3b) (or (2) if Depends.profiles is set).
- const bool profileMatch = !profilesPropertyIsSet || profiles.empty()
- || profiles.contains(dependency->profileName);
- if (profileMatch)
- multiplexIds << depMultiplexId;
- }
- if (!multiplexIds.empty()) {
- dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
- VariantValue::create(multiplexIds));
+ } else {
+ // Otherwise collect partial matches and decide later
+ const auto dependencyMultiplexConfig =
+ MultiplexInfo::multiplexIdToVariantMap(dependency->multiplexConfigurationId);
+
+ if (multiplexConfigurationIntersects(dependencyMultiplexConfig, productMultiplexConfig))
+ multiplexIds << dependency->multiplexConfigurationId;
+ }
+ } else {
+ // (2b), (3b) or (3c)
+ const bool profileMatch = !profilesPropertyIsSet || profiles.empty()
+ || profiles.contains(dependency->profileName);
+ if (profileMatch)
+ multiplexIds << depMultiplexId;
+ }
}
+ if (multiplexIds.empty()) {
+ const QString productName = ResolvedProduct::fullDisplayName(
+ product.name, product.multiplexConfigurationId);
+ throw ErrorInfo(Tr::tr("Dependency from product '%1' to product '%2' not fulfilled. "
+ "There are no eligible multiplex candidates.").arg(productName,
+ name),
+ dependsItem->location());
+ }
+
+ // In case of (2a), at most 1 match is allowed
+ if (productIsMultiplexed && !profilesPropertyIsSet && multiplexIds.size() > 1) {
+ const QString productName = ResolvedProduct::fullDisplayName(
+ product.name, product.multiplexConfigurationId);
+ QStringList candidateNames;
+ for (const auto &id : qAsConst(multiplexIds))
+ candidateNames << ResolvedProduct::fullDisplayName(name, id);
+ throw ErrorInfo(Tr::tr("Dependency from product '%1' to product '%2' is ambiguous. "
+ "Eligible multiplex candidates: %3.").arg(
+ productName, name, candidateNames.join(QLatin1String(", "))),
+ dependsItem->location());
+ }
+
+ dependsItem->setProperty(StringConstants::multiplexConfigurationIdsProperty(),
+ VariantValue::create(multiplexIds));
}
void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productItem)
@@ -1216,7 +1296,8 @@ void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productI
// evaluate the product's exported properties in isolation in the project resolver.
Item * const importer = Item::create(productItem->pool(), ItemType::Product);
importer->setProperty(QStringLiteral("name"),
- VariantValue::create(shadowProductPrefix() + productContext.name));
+ VariantValue::create(StringConstants::shadowProductPrefix()
+ + productContext.name));
importer->setFile(productItem->file());
importer->setLocation(productItem->location());
importer->setScope(projectContext->scope);
@@ -1281,7 +1362,6 @@ void ModuleLoader::createSortedModuleList(const Item::Module &parentModule, Item
for (const Item::Module &dep : parentModule.item->modules())
createSortedModuleList(dep, modules);
modules.push_back(parentModule);
- return;
}
Item::Modules ModuleLoader::modulesSortedByDependency(const Item *productItem)
@@ -1350,8 +1430,7 @@ void ModuleLoader::handleProduct(ModuleLoader::ProductContext *productContext)
// 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();
+ ModuleMerger::merge(m_logger, item, productContext->name, &topSortedModules);
// 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,
@@ -1585,7 +1664,7 @@ void ModuleLoader::handleSubProject(ModuleLoader::ProjectContext *projectContext
const Item::PropertyMap &overriddenProperties = propertiesItem->properties();
for (Item::PropertyMap::ConstIterator it = overriddenProperties.constBegin();
it != overriddenProperties.constEnd(); ++it) {
- loadedItem->setProperty(it.key(), overriddenProperties.value(it.key()));
+ loadedItem->setProperty(it.key(), it.value());
}
}
@@ -1806,7 +1885,7 @@ ProbeConstPtr ModuleLoader::findCurrentProbe(
bool condition,
const QVariantMap &initialProperties) const
{
- const QList<ProbeConstPtr> &cachedProbes = m_currentProbes.value(location);
+ const std::vector<ProbeConstPtr> &cachedProbes = m_currentProbes.value(location);
for (const ProbeConstPtr &probe : cachedProbes) {
if (probeMatches(probe, condition, initialProperties, QString(), CompareScript::No))
return probe;
@@ -1964,7 +2043,7 @@ bool ModuleLoader::mergeExportItems(const ProductContext &productContext)
productContext.project->topLevelProject->productModules.insert(productContext.name, pmi);
if (hasDependenciesOnProductType)
m_exportsWithDeferredDependsItems.insert(merged);
- return exportItems.size() > 0;
+ return !exportItems.empty();
}
Item *ModuleLoader::loadItemFromFile(const QString &filePath,
@@ -2171,9 +2250,10 @@ void ModuleLoader::setSearchPathsForProduct(ModuleLoader::ProductContext *produc
ModuleLoader::ShadowProductInfo ModuleLoader::getShadowProductInfo(
const ModuleLoader::ProductContext &product) const
{
- const bool isShadowProduct = product.name.startsWith(shadowProductPrefix());
+ const bool isShadowProduct = product.name.startsWith(StringConstants::shadowProductPrefix());
return std::make_pair(isShadowProduct, isShadowProduct
- ? product.name.mid(shadowProductPrefix().size()) : QString());
+ ? product.name.mid(StringConstants::shadowProductPrefix().size())
+ : QString());
}
void ModuleLoader::collectProductsByName(const TopLevelProjectContext &topLevelProject)
@@ -2705,7 +2785,7 @@ void ModuleLoader::resolveParameterDeclarations(const Item *module)
for (Item *param : moduleChildren) {
if (param->type() != ItemType::Parameter)
continue;
- const auto paramDecls = param->propertyDeclarations();
+ const auto &paramDecls = param->propertyDeclarations();
for (auto it = paramDecls.begin(); it != paramDecls.end(); ++it)
decls.insert(it.key(), it.value());
}
@@ -2756,7 +2836,8 @@ QVariantMap ModuleLoader::extractParameters(Item *dependsItem) const
QScriptValue sv = m_evaluator->scriptValue(dependsItem);
try {
result = safeToVariant(sv);
- } catch (ErrorInfo ei) {
+ } catch (const ErrorInfo &exception) {
+ auto ei = exception;
ei.prepend(Tr::tr("Error in dependency parameter."), dependsItem->location());
throw ei;
}
@@ -3024,72 +3105,67 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
const CodeLocation &dependsItemLocation, const QualifiedId &moduleName,
FallbackMode fallbackMode, bool isRequired, Item *moduleInstance)
{
- bool triedToLoadModule = false;
+ auto existingPaths = findExistingModulePaths(m_reader->allSearchPaths(), moduleName);
+
+ if (existingPaths.isEmpty()) { // no suitable names found, try to use providers
+ bool moduleAlreadyKnown = false;
+ ModuleProviderResult result;
+ for (QualifiedId providerName = moduleName; !providerName.empty();
+ providerName.pop_back()) {
+ if (!productContext->knownModuleProviders.insert(providerName).second) {
+ moduleAlreadyKnown = true;
+ break;
+ }
+ qCDebug(lcModuleLoader) << "Module" << moduleName.toString()
+ << "not found, checking for module providers";
+ result = findModuleProvider(providerName, *productContext,
+ ModuleProviderLookup::Regular, dependsItemLocation);
+ if (result.providerFound)
+ break;
+ }
+ if (fallbackMode == FallbackMode::Enabled && !result.providerFound
+ && !moduleAlreadyKnown) {
+ qCDebug(lcModuleLoader) << "Specific module provider not found for"
+ << moduleName.toString() << ", setting up fallback.";
+ result = findModuleProvider(moduleName, *productContext,
+ ModuleProviderLookup::Fallback, dependsItemLocation);
+ }
+ if (result.providerAddedSearchPaths) {
+ qCDebug(lcModuleLoader) << "Re-checking for module" << moduleName.toString()
+ << "with newly added search paths from module provider";
+ existingPaths = findExistingModulePaths(m_reader->allSearchPaths(), moduleName);
+ }
+ }
+
const QString fullName = moduleName.toString();
+ bool triedToLoadModule = false;
std::vector<PrioritizedItem> candidates;
- const QStringList &searchPaths = m_reader->allSearchPaths();
- bool matchingDirectoryFound = false;
- for (int i = 0; i < searchPaths.size(); ++i) {
- const QString &path = searchPaths.at(i);
- const QString dirPath = findExistingModulePath(path, moduleName);
- if (dirPath.isEmpty())
- continue;
- matchingDirectoryFound = true;
- QStringList moduleFileNames = m_moduleDirListCache.value(dirPath);
- if (moduleFileNames.empty()) {
- QDirIterator dirIter(dirPath, StringConstants::qbsFileWildcards());
- while (dirIter.hasNext())
- moduleFileNames += dirIter.next();
-
- m_moduleDirListCache.insert(dirPath, moduleFileNames);
- }
- for (const QString &filePath : qAsConst(moduleFileNames)) {
- triedToLoadModule = true;
+ candidates.reserve(size_t(existingPaths.size()));
+ for (int i = 0; i < existingPaths.size(); ++i) {
+ const QString &dirPath = existingPaths.at(i);
+ QStringList &moduleFileNames = getModuleFileNames(dirPath);
+ for (auto it = moduleFileNames.begin(); it != moduleFileNames.end(); ) {
+ const QString &filePath = *it;
+ bool triedToLoad = true;
Item *module = loadModuleFile(productContext, fullName, isBaseModule(moduleName),
- filePath, &triedToLoadModule, moduleInstance);
+ filePath, &triedToLoad, moduleInstance);
if (module)
candidates.emplace_back(module, 0, i);
- if (!triedToLoadModule)
- m_moduleDirListCache[dirPath].removeOne(filePath);
+ if (!triedToLoad)
+ it = moduleFileNames.erase(it);
+ else
+ ++it;
+ triedToLoadModule = triedToLoadModule || triedToLoad;
}
}
if (candidates.empty()) {
- if (!matchingDirectoryFound) {
- bool moduleAlreadyKnown = false;
- ModuleProviderResult result;
- for (QualifiedId providerName = moduleName; !providerName.empty();
- providerName.pop_back()) {
- if (!productContext->knownModuleProviders.insert(providerName).second) {
- moduleAlreadyKnown = true;
- break;
- }
- qCDebug(lcModuleLoader) << "Module" << moduleName.toString()
- << "not found, checking for module providers";
- result = findModuleProvider(providerName, *productContext,
- ModuleProviderLookup::Regular, dependsItemLocation);
- if (result.providerFound)
- break;
- }
- if (fallbackMode == FallbackMode::Enabled && !result.providerFound
- && !moduleAlreadyKnown) {
- qCDebug(lcModuleLoader) << "Specific module provider not found for"
- << moduleName.toString() << ", setting up fallback.";
- result = findModuleProvider(moduleName, *productContext,
- ModuleProviderLookup::Fallback, dependsItemLocation);
- }
- if (result.providerAddedSearchPaths) {
- qCDebug(lcModuleLoader) << "Re-checking for module" << moduleName.toString()
- << "with newly added search paths from module provider";
- return searchAndLoadModuleFile(productContext, dependsItemLocation, moduleName,
- fallbackMode, isRequired, moduleInstance);
- }
- }
if (!isRequired)
return createNonPresentModule(fullName, QStringLiteral("not found"), nullptr);
- if (Q_UNLIKELY(triedToLoadModule))
+ if (Q_UNLIKELY(triedToLoadModule)) {
throw ErrorInfo(Tr::tr("Module %1 could not be loaded.").arg(fullName),
dependsItemLocation);
+ }
return nullptr;
}
@@ -3119,6 +3195,17 @@ Item *ModuleLoader::searchAndLoadModuleFile(ProductContext *productContext,
return moduleItem;
}
+QStringList &ModuleLoader::getModuleFileNames(const QString &dirPath)
+{
+ QStringList &moduleFileNames = m_moduleDirListCache[dirPath];
+ if (moduleFileNames.empty()) {
+ QDirIterator dirIter(dirPath, StringConstants::qbsFileWildcards());
+ while (dirIter.hasNext())
+ moduleFileNames += dirIter.next();
+ }
+ return moduleFileNames;
+}
+
// returns QVariant::Invalid for types that do not need conversion
static QVariant::Type variantType(PropertyDeclaration::Type t)
{
@@ -3227,7 +3314,7 @@ Item *ModuleLoader::getModulePrototype(ProductContext *productContext,
}
}
Item * const module = loadItemFromFile(filePath, CodeLocation());
- prototypeList.push_back(std::make_pair(module, productContext->profileName));
+ prototypeList.emplace_back(module, productContext->profileName);
if (module->type() != ItemType::Module) {
qCDebug(lcModuleLoader).nospace()
<< "Alleged module " << fullModuleName << " has type '"
@@ -3285,6 +3372,9 @@ void ModuleLoader::setupBaseModulePrototype(Item *prototype)
prototype->setProperty(QStringLiteral("hostPlatform"),
VariantValue::create(QString::fromStdString(
HostOsInfo::hostOSIdentifier())));
+ prototype->setProperty(QStringLiteral("hostArchitecture"),
+ VariantValue::create(QString::fromStdString(
+ HostOsInfo::hostOSArchitecture())));
prototype->setProperty(QStringLiteral("libexecPath"),
VariantValue::create(m_parameters.libexecPath()));
@@ -3327,7 +3417,7 @@ static std::vector<std::pair<QualifiedId, ItemValuePtr>> instanceItemProperties(
if (itemValue->item()->type() == ItemType::ModulePrefix)
f(itemValue->item());
else
- result.push_back(std::make_pair(name, itemValue));
+ result.emplace_back(name, itemValue);
name.removeLast();
}
};
@@ -3496,7 +3586,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
if (Q_UNLIKELY(configureScript->sourceCode() == StringConstants::undefinedValue()))
throw ErrorInfo(Tr::tr("Probe.configure must be set."), probe->location());
using ProbeProperty = std::pair<QString, QScriptValue>;
- QList<ProbeProperty> probeBindings;
+ std::vector<ProbeProperty> probeBindings;
QVariantMap initialProperties;
for (Item *obj = probe; obj; obj = obj->prototype()) {
const Item::PropertyMap &props = obj->properties();
@@ -3505,7 +3595,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
if (name == StringConstants::configureProperty())
continue;
const QScriptValue value = m_evaluator->value(probe, name);
- probeBindings += ProbeProperty(name, value);
+ probeBindings << ProbeProperty(name, value);
if (name != StringConstants::conditionProperty())
initialProperties.insert(name, value.toVariant());
}
@@ -3516,7 +3606,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
const QString &sourceCode = configureScript->sourceCode().toString();
ProbeConstPtr resolvedProbe;
if (parent->type() == ItemType::Project
- || productContext->name.startsWith(shadowProductPrefix())) {
+ || productContext->name.startsWith(StringConstants::shadowProductPrefix())) {
resolvedProbe = findOldProjectProbe(probeId, condition, initialProperties, sourceCode);
} else {
const QString &uniqueProductName = productContext->uniqueName();
@@ -3544,7 +3634,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
engine->currentContext()->pushScope(fileCtxScopes.fileScope);
engine->currentContext()->pushScope(fileCtxScopes.importScope);
configureScope = engine->newObject();
- for (const ProbeProperty &b : qAsConst(probeBindings))
+ for (const ProbeProperty &b : probeBindings)
configureScope.setProperty(b.first, b.second);
engine->currentContext()->pushScope(configureScope);
engine->clearRequestedProperties();
@@ -3560,7 +3650,7 @@ void ModuleLoader::resolveProbe(ProductContext *productContext, Item *parent, It
importedFilesUsedInConfigure = resolvedProbe->importedFilesUsed();
}
QVariantMap properties;
- for (const ProbeProperty &b : qAsConst(probeBindings)) {
+ for (const ProbeProperty &b : probeBindings) {
QVariant newValue;
if (resolvedProbe) {
newValue = resolvedProbe->properties().value(b.first);
@@ -3678,12 +3768,36 @@ QString ModuleLoader::findExistingModulePath(const QString &searchPath,
const QualifiedId &moduleName)
{
QString dirPath = searchPath + QStringLiteral("/modules");
+
+ // isFileCaseCorrect is a very expensive call on macOS, so we cache the value for the
+ // modules and search paths we've already processed
+ auto &moduleInfo = m_existingModulePathCache[{searchPath, moduleName}];
+ if (moduleInfo.first) // poor man's std::optional<QString>
+ return moduleInfo.second;
+
for (const QString &moduleNamePart : moduleName) {
dirPath = FileInfo::resolvePath(dirPath, moduleNamePart);
- if (!FileInfo::exists(dirPath) || !FileInfo::isFileCaseCorrect(dirPath))
- return {};
+ if (!FileInfo::exists(dirPath) || !FileInfo::isFileCaseCorrect(dirPath)) {
+ moduleInfo.first = true;
+ return moduleInfo.second = QString();
+ }
}
- return dirPath;
+
+ moduleInfo.first = true;
+ return moduleInfo.second = dirPath;
+}
+
+QStringList ModuleLoader::findExistingModulePaths(
+ const QStringList &searchPaths, const QualifiedId &moduleName)
+{
+ QStringList result;
+ result.reserve(searchPaths.size());
+ for (const auto &path: searchPaths) {
+ const QString dirPath = findExistingModulePath(path, moduleName);
+ if (!dirPath.isEmpty())
+ result.append(dirPath);
+ }
+ return result;
}
QVariantMap ModuleLoader::moduleProviderConfig(ModuleLoader::ProductContext &product)
@@ -3769,6 +3883,7 @@ ModuleLoader::ModuleProviderResult ModuleLoader::findModuleProvider(const Qualif
const QString searchPathBaseDir = ModuleProviderInfo::outputDirPath(projectBuildDir, name);
const QVariant moduleConfig = moduleProviderConfig(product).value(name.toString());
QTextStream stream(&dummyItemFile);
+ using Qt::endl;
stream.setCodec("UTF-8");
stream << "import qbs.FileInfo" << endl;
stream << "import qbs.Utilities" << endl;
diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h
index 85a2467f2..942f93c83 100644
--- a/src/lib/corelib/language/moduleloader.h
+++ b/src/lib/corelib/language/moduleloader.h
@@ -218,7 +218,7 @@ private:
{
Q_DISABLE_COPY(TopLevelProjectContext)
public:
- TopLevelProjectContext() {}
+ TopLevelProjectContext() = default;
~TopLevelProjectContext() { qDeleteAll(projects); }
std::vector<ProjectContext *> projects;
@@ -252,6 +252,7 @@ private:
VariantValuePtr multiplexedType;
QString toIdString(size_t row) const;
+ static QVariantMap multiplexIdToVariantMap(const QString &multiplexId);
};
void dump(const MultiplexInfo &mpi);
@@ -317,6 +318,7 @@ private:
Item *searchAndLoadModuleFile(ProductContext *productContext,
const CodeLocation &dependsItemLocation, const QualifiedId &moduleName,
FallbackMode fallbackMode, bool isRequired, Item *moduleInstance);
+ QStringList &getModuleFileNames(const QString &dirPath);
Item *loadModuleFile(ProductContext *productContext, const QString &fullModuleName,
bool isBaseModule, const QString &filePath, bool *triedToLoad, Item *moduleInstance);
Item *getModulePrototype(ProductContext *productContext, const QString &fullModuleName,
@@ -337,8 +339,9 @@ private:
QStringList readExtraSearchPaths(Item *item, bool *wasSet = nullptr);
void copyProperties(const Item *sourceProject, Item *targetProject);
Item *wrapInProjectIfNecessary(Item *item);
- static QString findExistingModulePath(const QString &searchPath,
- const QualifiedId &moduleName);
+ QString findExistingModulePath(const QString &searchPath, const QualifiedId &moduleName);
+ QStringList findExistingModulePaths(
+ const QStringList &searchPaths, const QualifiedId &moduleName);
enum class ModuleProviderLookup { Regular, Fallback };
struct ModuleProviderResult
@@ -411,6 +414,7 @@ private:
ItemReader *m_reader;
Evaluator *m_evaluator;
QMap<QString, QStringList> m_moduleDirListCache;
+ QHash<std::pair<QString, QualifiedId>, std::pair<bool, QString>> m_existingModulePathCache;
// The keys are file paths, the values are module prototype items accompanied by a profile.
std::unordered_map<QString, std::vector<std::pair<Item *, QString>>> m_modulePrototypes;
@@ -425,8 +429,8 @@ private:
struct DependsChainEntry
{
- DependsChainEntry(const QualifiedId &name, const CodeLocation &location)
- : name(name), location(location)
+ DependsChainEntry(QualifiedId name, const CodeLocation &location)
+ : name(std::move(name)), location(location)
{
}
@@ -437,10 +441,10 @@ private:
class DependsChainManager;
std::vector<DependsChainEntry> m_dependsChain;
- QHash<QString, QList<ProbeConstPtr>> m_oldProjectProbes;
+ QHash<QString, std::vector<ProbeConstPtr>> m_oldProjectProbes;
QHash<QString, std::vector<ProbeConstPtr>> m_oldProductProbes;
FileTime m_lastResolveTime;
- QHash<CodeLocation, QList<ProbeConstPtr>> m_currentProbes;
+ QHash<CodeLocation, std::vector<ProbeConstPtr>> m_currentProbes;
QVariantMap m_storedProfiles;
QVariantMap m_localProfiles;
std::multimap<QString, const ProductContext *> m_productsByName;
diff --git a/src/lib/corelib/language/modulemerger.cpp b/src/lib/corelib/language/modulemerger.cpp
index 053e90d53..c5deaae04 100644
--- a/src/lib/corelib/language/modulemerger.cpp
+++ b/src/lib/corelib/language/modulemerger.cpp
@@ -50,15 +50,18 @@
namespace qbs {
namespace Internal {
-ModuleMerger::ModuleMerger(Logger &logger, Item *root, Item::Module &moduleToMerge)
+ModuleMerger::ModuleMerger(Logger &logger, Item *productItem, const QString &productName,
+ const Item::Modules::iterator &modulesBegin,
+ const Item::Modules::iterator &modulesEnd)
: m_logger(logger)
- , m_rootItem(root)
- , m_mergedModule(moduleToMerge)
- , m_required(moduleToMerge.required)
- , m_isBaseModule(moduleToMerge.name.first() == StringConstants::qbsModule())
- , m_versionRange(moduleToMerge.versionRange)
+ , m_productItem(productItem)
+ , m_mergedModule(*modulesBegin)
+ , m_isBaseModule(m_mergedModule.name.first() == StringConstants::qbsModule())
+ , m_isShadowProduct(productName.startsWith(StringConstants::shadowProductPrefix()))
+ , m_modulesBegin(std::next(modulesBegin))
+ , m_modulesEnd(modulesEnd)
{
- QBS_CHECK(moduleToMerge.item->type() == ItemType::ModuleInstance);
+ QBS_CHECK(modulesBegin->item->type() == ItemType::ModuleInstance);
}
void ModuleMerger::replaceItemInValues(QualifiedId moduleName, Item *containerItem, Item *toReplace)
@@ -83,48 +86,39 @@ void ModuleMerger::replaceItemInValues(QualifiedId moduleName, Item *containerIt
}
}
-void ModuleMerger::replaceItemInScopes(Item *toReplace)
-{
- // In insertProperties(), we potentially call setDefiningItem() with the "wrong"
- // (to-be-replaced) module instance as an argument. If such module instances
- // are dependencies of other modules, they have the depending module's instance
- // as their "instance scope", which is the scope of their scope. This function takes
- // care that the "wrong" definingItem of values in sub-modules still has the "right"
- // instance scope, namely our merged module instead of some other instance.
- for (const Item::Module &module : toReplace->modules()) {
- for (const ValuePtr &property : module.item->properties()) {
- ValuePtr v = property;
- do {
- if (v->definingItem() && v->definingItem()->scope()
- && v->definingItem()->scope()->scope() == toReplace) {
- v->definingItem()->scope()->setScope(m_mergedModule.item);
- }
- v = v->next();
- } while (v);
- }
- }
-}
-
void ModuleMerger::start()
{
+ // Iterate over any module that our product depends on. These modules
+ // may depend on m_mergedModule and contribute property assignments.
+ Item::PropertyMap props;
+ for (auto module = m_modulesBegin; module != m_modulesEnd; module++)
+ mergeModule(&props, *module);
+
+ // Module property assignments in the product have the highest priority
+ // and are thus prepended.
Item::Module m;
- m.item = m_rootItem;
- const Item::PropertyMap props = dfs(m, Item::PropertyMap());
- if (m_required)
- m_mergedModule.required = true;
- m_mergedModule.versionRange.narrowDown(m_versionRange);
- Item::PropertyMap mergedProps = m_mergedModule.item->properties();
+ m.item = m_productItem;
+ mergeModule(&props, m);
+ // The module's prototype is the essential unmodified module as loaded
+ // from the cache.
Item *moduleProto = m_mergedModule.item->prototype();
while (moduleProto->prototype())
moduleProto = moduleProto->prototype();
+ // The prototype item might contain default values which get appended in
+ // case of list properties. Scalar properties will only be set if not
+ // already specified above.
+ Item::PropertyMap mergedProps = m_mergedModule.item->properties();
for (auto it = props.constBegin(); it != props.constEnd(); ++it) {
appendPrototypeValueToNextChain(moduleProto, it.key(), it.value());
mergedProps[it.key()] = it.value();
}
+
m_mergedModule.item->setProperties(mergedProps);
+ // Update all sibling instances of the to-be-merged module to behave identical
+ // to the merged module.
for (Item *moduleInstanceContainer : qAsConst(m_moduleInstanceContainers)) {
Item::Modules modules;
for (const Item::Module &dep : moduleInstanceContainer->modules()) {
@@ -133,11 +127,9 @@ void ModuleMerger::start()
if (isTheModule && m.item != m_mergedModule.item) {
QBS_CHECK(m.item->type() == ItemType::ModuleInstance);
replaceItemInValues(m.name, moduleInstanceContainer, m.item);
- replaceItemInScopes(m.item);
m.item = m_mergedModule.item;
- if (m_required)
- m.required = true;
- m.versionRange.narrowDown(m_versionRange);
+ m.required = m_mergedModule.required;
+ m.versionRange = m_mergedModule.versionRange;
}
modules << m;
}
@@ -145,94 +137,26 @@ void ModuleMerger::start()
}
}
-Item::PropertyMap ModuleMerger::dfs(const Item::Module &m, Item::PropertyMap props)
+void ModuleMerger::mergeModule(Item::PropertyMap *dstProps, const Item::Module &module)
{
- Item *moduleInstance = nullptr;
- size_t numberOfOutprops = m.item->modules().size();
- for (const Item::Module &dep : m.item->modules()) {
- if (dep.name == m_mergedModule.name) {
- --numberOfOutprops;
- moduleInstance = dep.item;
- insertProperties(&props, moduleInstance, ScalarProperties);
- m_moduleInstanceContainers << m.item;
- if (dep.required)
- m_required = true;
- m_versionRange.narrowDown(dep.versionRange);
- break;
- }
- }
-
- std::vector<Item::PropertyMap> outprops;
- outprops.reserve(numberOfOutprops);
- for (const Item::Module &dep : m.item->modules()) {
- if (dep.item != moduleInstance)
- outprops.push_back(dfs(dep, props));
- }
-
- if (!outprops.empty()) {
- props = outprops.front();
- for (size_t i = 1; i < outprops.size(); ++i)
- mergeOutProps(&props, outprops.at(i));
- }
-
- if (moduleInstance)
- insertProperties(&props, moduleInstance, ListProperties);
-
- const bool isNonPresentModule = m.item->type() != ItemType::Product
- && !m.item->isPresentModule();
- return isNonPresentModule ? Item::PropertyMap() : props;
-}
-
-void ModuleMerger::mergeOutProps(Item::PropertyMap *dst, const Item::PropertyMap &src)
-{
- for (auto it = src.constBegin(); it != src.constEnd(); ++it) {
- ValuePtr &v = (*dst)[it.key()];
- if (!v) {
- v = it.value();
- QBS_ASSERT(it.value(), continue);
- continue;
- }
- if (v->type() != Value::JSSourceValueType)
- continue;
- if (it.value()->type() != Value::JSSourceValueType)
- continue;
- // possible conflict
- const JSSourceValuePtr dstVal = std::static_pointer_cast<JSSourceValue>(v);
- JSSourceValuePtr srcVal = std::static_pointer_cast<JSSourceValue>(it.value());
-
- const PropertyDeclaration pd = m_decls.value(srcVal);
- QBS_CHECK(pd.isValid());
-
- if (pd.isScalar()) {
- if (dstVal->sourceCode() != srcVal->sourceCode()) {
- m_logger.qbsWarning() << Tr::tr("Conflicting scalar values at %1 and %2.").arg(
- dstVal->location().toString(),
- srcVal->location().toString());
- // TODO: yield error with a hint how to solve the conflict.
- }
- v = it.value();
- } else {
- lastInNextChain(dstVal)->setNext(srcVal);
- }
- }
-}
+ const Item::Module *dep = findModule(module.item, m_mergedModule.name);
+ if (!dep)
+ return;
-void ModuleMerger::insertProperties(Item::PropertyMap *dst, Item *srcItem, PropertiesType type)
-{
- Set<const Item *> &seenInstances = type == ScalarProperties
- ? m_seenInstancesTopDown : m_seenInstancesBottomUp;
+ const bool mergingProductItem = (module.item == m_productItem);
+ Item *srcItem = dep->item;
Item *origSrcItem = srcItem;
do {
- if (seenInstances.insert(srcItem).second) {
- for (Item::PropertyMap::const_iterator it = srcItem->properties().constBegin();
- it != srcItem->properties().constEnd(); ++it) {
+ if (m_seenInstances.insert(srcItem).second) {
+ for (auto it = srcItem->properties().constBegin();
+ it != srcItem->properties().constEnd(); ++it) {
const ValuePtr &srcVal = it.value();
if (srcVal->type() == Value::ItemValueType)
continue;
if (it.key() == StringConstants::qbsSourceDirPropertyInternal())
continue;
const PropertyDeclaration srcDecl = srcItem->propertyDeclaration(it.key());
- if (!srcDecl.isValid() || srcDecl.isScalar() != (type == ScalarProperties))
+ if (!srcDecl.isValid())
continue;
// Scalar variant values could stem from product multiplexing, in which case
@@ -242,21 +166,51 @@ void ModuleMerger::insertProperties(Item::PropertyMap *dst, Item *srcItem, Prope
continue;
}
- ValuePtr &v = (*dst)[it.key()];
- if (v && type == ScalarProperties)
- continue;
- ValuePtr clonedVal = srcVal->clone();
- m_decls[clonedVal] = srcDecl;
- clonedVal->setDefiningItem(origSrcItem);
- if (v) {
- QBS_CHECK(!clonedVal->next());
- clonedVal->setNext(v);
+ ValuePtr clonedSrcVal = srcVal->clone();
+ clonedSrcVal->setDefiningItem(origSrcItem);
+
+ ValuePtr &dstVal = (*dstProps)[it.key()];
+ if (dstVal) {
+ if (srcDecl.isScalar()) {
+ // Scalar properties get replaced.
+ if ((dstVal->type() == Value::JSSourceValueType)
+ && (srcVal->type() == Value::JSSourceValueType)) {
+ // Warn only about conflicting source code values
+ const JSSourceValuePtr dstJsVal =
+ std::static_pointer_cast<JSSourceValue>(dstVal);
+ const JSSourceValuePtr srcJsVal =
+ std::static_pointer_cast<JSSourceValue>(srcVal);
+ const bool overriddenInProduct =
+ m_mergedModule.item->properties().contains(it.key());
+
+ if (dstJsVal->sourceCode() != srcJsVal->sourceCode()
+ && !mergingProductItem && !overriddenInProduct
+ && !m_isShadowProduct) {
+ m_logger.qbsWarning()
+ << Tr::tr("Conflicting scalar values at %1 and %2.").arg(
+ dstJsVal->location().toString(),
+ srcJsVal->location().toString());
+ }
+ }
+ } else {
+ // List properties get prepended
+ QBS_CHECK(!clonedSrcVal->next());
+ clonedSrcVal->setNext(dstVal);
+ }
}
- v = clonedVal;
+ dstVal = clonedSrcVal;
}
}
srcItem = srcItem->prototype();
} while (srcItem && srcItem->type() == ItemType::ModuleInstance);
+
+ // Update dependency constraints
+ if (dep->required)
+ m_mergedModule.required = true;
+ m_mergedModule.versionRange.narrowDown(dep->versionRange);
+
+ // We need to touch the unmerged module instances later once more
+ m_moduleInstanceContainers << module.item;
}
void ModuleMerger::appendPrototypeValueToNextChain(Item *moduleProto, const QString &propertyName,
@@ -288,5 +242,23 @@ ValuePtr ModuleMerger::lastInNextChain(const ValuePtr &v)
return n;
}
+const Item::Module *ModuleMerger::findModule(const Item *item, const QualifiedId &name)
+{
+ for (const auto &module : item->modules()) {
+ if (module.name == name)
+ return &module;
+ }
+ return nullptr;
+}
+
+void ModuleMerger::merge(Logger &logger, Item *product, const QString &productName,
+ Item::Modules *topSortedModules)
+{
+ for (auto it = topSortedModules->begin(); it != topSortedModules->end(); ++it)
+ ModuleMerger(logger, product, productName, it, topSortedModules->end()).start();
+}
+
+
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/modulemerger.h b/src/lib/corelib/language/modulemerger.h
index 3cc3ba08a..469dc86c4 100644
--- a/src/lib/corelib/language/modulemerger.h
+++ b/src/lib/corelib/language/modulemerger.h
@@ -54,32 +54,33 @@ namespace Internal {
class ModuleMerger {
public:
- ModuleMerger(Logger &logger, Item *root, Item::Module &moduleToMerge);
- void start();
+ static void merge(Logger &logger, Item *productItem, const QString &productName,
+ Item::Modules *topSortedModules);
private:
- Item::PropertyMap dfs(const Item::Module &m, Item::PropertyMap props);
- void mergeOutProps(Item::PropertyMap *dst, const Item::PropertyMap &src);
+ ModuleMerger(Logger &logger, Item *productItem, const QString &productName,
+ const Item::Modules::iterator &modulesBegin,
+ const Item::Modules::iterator &modulesEnd);
+
void appendPrototypeValueToNextChain(Item *moduleProto, const QString &propertyName,
const ValuePtr &sv);
- static ValuePtr lastInNextChain(const ValuePtr &v);
-
- enum PropertiesType { ScalarProperties, ListProperties };
- void insertProperties(Item::PropertyMap *dst, Item *srcItem, PropertiesType type);
+ void mergeModule(Item::PropertyMap *props, const Item::Module &m);
void replaceItemInValues(QualifiedId moduleName, Item *containerItem, Item *toReplace);
- void replaceItemInScopes(Item *toReplace);
+ void start();
+
+ static ValuePtr lastInNextChain(const ValuePtr &v);
+ static const Item::Module *findModule(const Item *item, const QualifiedId &name);
Logger &m_logger;
- Item * const m_rootItem;
+ Item * const m_productItem;
Item::Module &m_mergedModule;
Item *m_clonedModulePrototype = nullptr;
- QHash<ValuePtr, PropertyDeclaration> m_decls;
- Set<const Item *> m_seenInstancesTopDown;
- Set<const Item *> m_seenInstancesBottomUp;
+ Set<const Item *> m_seenInstances;
Set<Item *> m_moduleInstanceContainers;
- bool m_required;
const bool m_isBaseModule;
- VersionRange m_versionRange;
+ const bool m_isShadowProduct;
+ const Item::Modules::iterator m_modulesBegin;
+ const Item::Modules::iterator m_modulesEnd;
};
} // namespace Internal
diff --git a/src/lib/corelib/language/moduleproviderinfo.h b/src/lib/corelib/language/moduleproviderinfo.h
index fef9d9765..4f757d3d9 100644
--- a/src/lib/corelib/language/moduleproviderinfo.h
+++ b/src/lib/corelib/language/moduleproviderinfo.h
@@ -55,9 +55,12 @@ class ModuleProviderInfo
{
public:
ModuleProviderInfo() = default;
- ModuleProviderInfo(const QualifiedId &name, const QVariantMap &config,
- const QStringList &searchPaths, bool transientOutput)
- : name(name), config(config), searchPaths(searchPaths), transientOutput(transientOutput)
+ ModuleProviderInfo(QualifiedId name, QVariantMap config,
+ QStringList searchPaths, bool transientOutput)
+ : name(std::move(name))
+ , config(std::move(config))
+ , searchPaths(std::move(searchPaths))
+ , transientOutput(transientOutput)
{}
static QString outputBaseDirName() { return QStringLiteral("genmodules"); }
diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp
index 049472310..fd6063381 100644
--- a/src/lib/corelib/language/projectresolver.cpp
+++ b/src/lib/corelib/language/projectresolver.cpp
@@ -71,6 +71,7 @@
#include <QtCore/qregexp.h>
#include <algorithm>
+#include <memory>
#include <queue>
namespace qbs {
@@ -126,9 +127,7 @@ ProjectResolver::ProjectResolver(Evaluator *evaluator, ModuleLoaderResult loadRe
QBS_CHECK(FileInfo::isAbsolute(m_setupParams.buildRoot()));
}
-ProjectResolver::~ProjectResolver()
-{
-}
+ProjectResolver::~ProjectResolver() = default;
void ProjectResolver::setProgressObserver(ProgressObserver *observer)
{
@@ -812,7 +811,7 @@ void ProjectResolver::resolveGroupFully(Item *item, ProjectResolver::ProjectCont
group->targetOfModule = moduleProp->value().toString();
ErrorInfo fileError;
if (!patterns.empty()) {
- group->wildcards = std::unique_ptr<SourceWildCards>(new SourceWildCards);
+ group->wildcards = std::make_unique<SourceWildCards>();
SourceWildCards *wildcards = group->wildcards.get();
wildcards->group = group.get();
wildcards->excludePatterns = m_evaluator->stringListValue(
@@ -988,7 +987,7 @@ void ProjectResolver::resolveShadowProduct(Item *item, ProjectResolver::ProjectC
try {
adaptExportedPropertyValues(item);
} catch (const ErrorInfo &) {}
- m_productExportInfo.push_back(std::make_pair(m_productContext->product, item));
+ m_productExportInfo.emplace_back(m_productContext->product, item);
}
void ProjectResolver::setupExportedProperties(const Item *item, const QString &namePrefix,
@@ -1460,7 +1459,7 @@ void ProjectResolver::matchArtifactProperties(const ResolvedProductPtr &product,
const std::vector<SourceArtifactPtr> &artifacts)
{
for (const SourceArtifactPtr &artifact : artifacts) {
- for (const ArtifactPropertiesConstPtr &artifactProperties : product->artifactProperties) {
+ for (const auto &artifactProperties : product->artifactProperties) {
if (!artifact->isTargetOfModule()
&& artifact->fileTags.intersects(artifactProperties->fileTagsFilter())) {
artifact->properties = artifactProperties->propertyMap();
diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h
index 428ba144d..a1e24a555 100644
--- a/src/lib/corelib/language/projectresolver.h
+++ b/src/lib/corelib/language/projectresolver.h
@@ -139,9 +139,9 @@ private:
struct ProductDependencyInfo
{
- ProductDependencyInfo(const ResolvedProductPtr &product,
- const QVariantMap &parameters = QVariantMap())
- : product(product), parameters(parameters)
+ ProductDependencyInfo(ResolvedProductPtr product,
+ QVariantMap parameters = QVariantMap())
+ : product(std::move(product)), parameters(std::move(parameters))
{
}
diff --git a/src/lib/corelib/language/property.h b/src/lib/corelib/language/property.h
index 204704672..78061bf6f 100644
--- a/src/lib/corelib/language/property.h
+++ b/src/lib/corelib/language/property.h
@@ -65,9 +65,13 @@ public:
{
}
- Property(const QString &product, const QString &module, const QString &property,
- const QVariant &v, Kind k)
- : productName(product), moduleName(module), propertyName(property), value(v), kind(k)
+ Property(QString product, QString module, QString property,
+ QVariant v, Kind k)
+ : productName(std::move(product))
+ , moduleName(std::move(module))
+ , propertyName(std::move(property))
+ , value(std::move(v))
+ , kind(k)
{
}
diff --git a/src/lib/corelib/language/propertydeclaration.cpp b/src/lib/corelib/language/propertydeclaration.cpp
index 5ea6a3d88..abe6a1626 100644
--- a/src/lib/corelib/language/propertydeclaration.cpp
+++ b/src/lib/corelib/language/propertydeclaration.cpp
@@ -84,20 +84,11 @@ PropertyDeclaration::PropertyDeclaration(const QString &name, Type type,
d->flags = flags;
}
-PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other)
- : d(other.d)
-{
-}
+PropertyDeclaration::PropertyDeclaration(const PropertyDeclaration &other) = default;
-PropertyDeclaration::~PropertyDeclaration()
-{
-}
+PropertyDeclaration::~PropertyDeclaration() = default;
-PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other)
-{
- d = other.d;
- return *this;
-}
+PropertyDeclaration &PropertyDeclaration::operator=(const PropertyDeclaration &other) = default;
bool PropertyDeclaration::isValid() const
{
diff --git a/src/lib/corelib/language/propertymapinternal.cpp b/src/lib/corelib/language/propertymapinternal.cpp
index 2a35e2a6a..fe0f672c5 100644
--- a/src/lib/corelib/language/propertymapinternal.cpp
+++ b/src/lib/corelib/language/propertymapinternal.cpp
@@ -58,13 +58,9 @@ namespace Internal {
* \sa ResolvedProduct
* \sa SourceArtifact
*/
-PropertyMapInternal::PropertyMapInternal()
-{
-}
+PropertyMapInternal::PropertyMapInternal() = default;
-PropertyMapInternal::PropertyMapInternal(const PropertyMapInternal &other) : m_value(other.m_value)
-{
-}
+PropertyMapInternal::PropertyMapInternal(const PropertyMapInternal &other) = default;
QVariant PropertyMapInternal::moduleProperty(const QString &moduleName, const QString &key,
bool *isPresent) const
diff --git a/src/lib/corelib/language/qualifiedid.cpp b/src/lib/corelib/language/qualifiedid.cpp
index 5cc315bb1..9eb0e9463 100644
--- a/src/lib/corelib/language/qualifiedid.cpp
+++ b/src/lib/corelib/language/qualifiedid.cpp
@@ -44,9 +44,7 @@
namespace qbs {
namespace Internal {
-QualifiedId::QualifiedId()
-{
-}
+QualifiedId::QualifiedId() = default;
QualifiedId::QualifiedId(const QString &singlePartName)
: QStringList(singlePartName)
diff --git a/src/lib/corelib/language/resolvedfilecontext.h b/src/lib/corelib/language/resolvedfilecontext.h
index 81a3f7472..d783cf725 100644
--- a/src/lib/corelib/language/resolvedfilecontext.h
+++ b/src/lib/corelib/language/resolvedfilecontext.h
@@ -65,7 +65,7 @@ public:
pool.serializationOp<opType>(m_filePath, m_jsExtensions, m_searchPaths, m_jsImports);
}
private:
- ResolvedFileContext() {}
+ ResolvedFileContext() = default;
ResolvedFileContext(const FileContextBase &ctx);
};
diff --git a/src/lib/corelib/language/scriptengine.cpp b/src/lib/corelib/language/scriptengine.cpp
index 7c531e764..e79ec54d7 100644
--- a/src/lib/corelib/language/scriptengine.cpp
+++ b/src/lib/corelib/language/scriptengine.cpp
@@ -478,19 +478,18 @@ QScriptValue ScriptEngine::js_require(QScriptContext *context, QScriptEngine *qt
return context->throwError(
ScriptEngine::tr("require: internal error. No search paths."));
- const QString uri = moduleName;
if (engine->m_logger.debugEnabled()) {
engine->m_logger.qbsDebug()
- << "[require] loading extension " << uri;
+ << "[require] loading extension " << moduleName;
}
- QString uriAsPath = uri;
- uriAsPath.replace(QLatin1Char('.'), QLatin1Char('/'));
+ QString moduleNameAsPath = moduleName;
+ moduleNameAsPath.replace(QLatin1Char('.'), QLatin1Char('/'));
const QStringList searchPaths = engine->m_extensionSearchPathsStack.top();
- const QString dirPath = findExtensionDir(searchPaths, uriAsPath);
+ const QString dirPath = findExtensionDir(searchPaths, moduleNameAsPath);
if (dirPath.isEmpty()) {
- if (uri.startsWith(QStringLiteral("qbs.")))
- return loadInternalExtension(context, engine, uri);
+ if (moduleName.startsWith(QStringLiteral("qbs.")))
+ return loadInternalExtension(context, engine, moduleName);
} else {
QDirIterator dit(dirPath, StringConstants::jsFileWildcards(),
QDir::Files | QDir::Readable);
diff --git a/src/lib/corelib/language/value.cpp b/src/lib/corelib/language/value.cpp
index 656f38874..342fbd89a 100644
--- a/src/lib/corelib/language/value.cpp
+++ b/src/lib/corelib/language/value.cpp
@@ -61,9 +61,7 @@ Value::Value(const Value &other)
{
}
-Value::~Value()
-{
-}
+Value::~Value() = default;
Item *Value::definingItem() const
{
@@ -115,9 +113,7 @@ JSSourceValuePtr JSSourceValue::create(bool createdByPropertiesBlock)
return JSSourceValuePtr(new JSSourceValue(createdByPropertiesBlock));
}
-JSSourceValue::~JSSourceValue()
-{
-}
+JSSourceValue::~JSSourceValue() = default;
ValuePtr JSSourceValue::clone() const
{
@@ -200,7 +196,7 @@ VariantValuePtr VariantValue::create(const QVariant &v)
ValuePtr VariantValue::clone() const
{
- return VariantValuePtr(new VariantValue(*this));
+ return std::make_shared<VariantValue>(*this);
}
const VariantValuePtr &VariantValue::falseValue()
diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h
index f27406f2d..d3a748d92 100644
--- a/src/lib/corelib/language/value.h
+++ b/src/lib/corelib/language/value.h
@@ -151,14 +151,14 @@ public:
struct PropertyData
{
PropertyData() = default;
- PropertyData(const QString &v, const CodeLocation &l) : value(v), location(l) {}
+ PropertyData(QString v, const CodeLocation &l) : value(std::move(v)), location(l) {}
QString value;
CodeLocation location;
};
- Alternative() { }
- Alternative(const PropertyData &c, const PropertyData &o, const JSSourceValuePtr &v)
- : condition(c), overrideListProperties(o), value(v) {}
+ Alternative() = default;
+ Alternative(PropertyData c, PropertyData o, JSSourceValuePtr v)
+ : condition(std::move(c)), overrideListProperties(std::move(o)), value(std::move(v)) {}
Alternative clone() const
{
return Alternative(condition, overrideListProperties,