diff options
Diffstat (limited to 'src/lib/corelib/language/modulepropertymerger.cpp')
-rw-r--r-- | src/lib/corelib/language/modulepropertymerger.cpp | 304 |
1 files changed, 0 insertions, 304 deletions
diff --git a/src/lib/corelib/language/modulepropertymerger.cpp b/src/lib/corelib/language/modulepropertymerger.cpp deleted file mode 100644 index d45329d12..000000000 --- a/src/lib/corelib/language/modulepropertymerger.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2023 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qbs. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "modulepropertymerger.h" - -#include "evaluator.h" -#include "item.h" -#include "value.h" - -#include <logging/translator.h> -#include <tools/profiling.h> -#include <tools/set.h> -#include <tools/setupprojectparameters.h> - -namespace qbs::Internal { -class ModulePropertyMerger::Private -{ -public: - Private(const SetupProjectParameters ¶meters, Evaluator &evaluator, Logger &logger) - : parameters(parameters), evaluator(evaluator), logger(logger) {} - - int compareValuePriorities(const Item *productItem, const ValueConstPtr &v1, - const ValueConstPtr &v2); - ValuePtr mergeListValues(const Item *productItem, const ValuePtr ¤tHead, const ValuePtr &newElem); - void mergePropertyFromLocalInstance(const Item *productItem, Item *loadingItem, - const QString &loadingName, Item *globalInstance, - const QString &name, const ValuePtr &value); - bool doFinalMerge(const Item *productItem, Item *moduleItem); - bool doFinalMerge(const Item *productItem, const PropertyDeclaration &propertyDecl, - ValuePtr &propertyValue); - - const SetupProjectParameters ¶meters; - Evaluator &evaluator; - Logger &logger; - qint64 elapsedTime = 0; -}; - -void ModulePropertyMerger::mergeFromLocalInstance( - const Item *productItem, Item *loadingItem, const QString &loadingName, - const Item *localInstance, Item *globalInstance) -{ - AccumulatingTimer t(d->parameters.logElapsedTime() ? &d->elapsedTime : nullptr); - - for (auto it = localInstance->properties().constBegin(); - it != localInstance->properties().constEnd(); ++it) { - d->mergePropertyFromLocalInstance(productItem, loadingItem, loadingName, - globalInstance, it.key(), it.value()); - } -} - -void ModulePropertyMerger::doFinalMerge(const Item *productItem) -{ - AccumulatingTimer t(d->parameters.logElapsedTime() ? &d->elapsedTime : nullptr); - - Set<const Item *> itemsToInvalidate; - for (const Item::Module &module : productItem->modules()) { - if (d->doFinalMerge(productItem, module.item)) - itemsToInvalidate << module.item; - } - const auto collectDependentItems = [&itemsToInvalidate](const Item *item, - const auto &collect) -> bool { - const bool alreadyInSet = itemsToInvalidate.contains(item); - bool addItem = false; - for (const Item::Module &m : item->modules()) { - if (collect(m.item, collect)) - addItem = true; - } - if (addItem && !alreadyInSet) - itemsToInvalidate << item; - return addItem || alreadyInSet; - }; - collectDependentItems(productItem, collectDependentItems); - for (const Item * const item : itemsToInvalidate) - d->evaluator.clearCache(item); -} - -void ModulePropertyMerger::printProfilingInfo(int indent) -{ - if (!d->parameters.logElapsedTime()) - return; - d->logger.qbsLog(LoggerInfo, true) << QByteArray(indent, ' ') - << Tr::tr("Merging module property values took %1.") - .arg(elapsedTimeString(d->elapsedTime)); -} - -ModulePropertyMerger::ModulePropertyMerger( - const SetupProjectParameters ¶meters, Evaluator &evaluator, Logger &logger) - : d(new Private(parameters, evaluator, logger)) { } -ModulePropertyMerger::~ModulePropertyMerger() { delete d; } - -int ModulePropertyMerger::Private::compareValuePriorities( - const Item *productItem, const ValueConstPtr &v1, const ValueConstPtr &v2) -{ - QBS_CHECK(v1); - QBS_CHECK(v2); - QBS_CHECK(v1->scope() != v2->scope()); - QBS_CHECK(v1->type() == Value::JSSourceValueType || v2->type() == Value::JSSourceValueType); - - const int prio1 = v1->priority(productItem); - const int prio2 = v2->priority(productItem); - if (prio1 != prio2) - return prio1 - prio2; - const int prioDiff = v1->scopeName().compare(v2->scopeName()); // Sic! See 8ff1dd0044 - QBS_CHECK(prioDiff != 0); - return prioDiff; -} - -ValuePtr ModulePropertyMerger::Private::mergeListValues( - const Item *productItem, const ValuePtr ¤tHead, const ValuePtr &newElem) -{ - QBS_CHECK(newElem); - QBS_CHECK(!newElem->next()); - - if (!currentHead) - return !newElem->expired(productItem) ? newElem : newElem->next(); - - QBS_CHECK(!currentHead->expired(productItem)); - - if (newElem->expired(productItem)) - return currentHead; - - if (compareValuePriorities(productItem, currentHead, newElem) < 0) { - newElem->setNext(currentHead); - return newElem; - } - currentHead->setNext(mergeListValues(productItem, currentHead->next(), newElem)); - return currentHead; -} - -void ModulePropertyMerger::Private::mergePropertyFromLocalInstance( - const Item *productItem, Item *loadingItem, const QString &loadingName, Item *globalInstance, - const QString &name, const ValuePtr &value) -{ - const PropertyDeclaration decl = globalInstance->propertyDeclaration(name); - if (!decl.isValid()) { - if (value->type() == Value::ItemValueType || value->createdByPropertiesBlock()) - return; - throw ErrorInfo(Tr::tr("Property '%1' is not declared.") - .arg(name), value->location()); - } - if (const ErrorInfo error = decl.checkForDeprecation( - parameters.deprecationWarningMode(), value->location(), logger); - error.hasError()) { - handlePropertyError(error, parameters, logger); - return; - } - if (value->setInternally()) { // E.g. qbs.architecture after multiplexing. - globalInstance->setProperty(decl.name(), value); - return; - } - QBS_CHECK(value->type() != Value::ItemValueType); - const ValuePtr globalVal = globalInstance->ownProperty(decl.name()); - value->setScope(loadingItem, loadingName); - QBS_CHECK(globalVal); - - // Values set internally cannot be overridden by JS values. - // The same goes for values set on the command line. - // Note that in both cases, there is no merging for list properties: The override is absolute. - if (globalVal->setInternally() || globalVal->setByCommandLine()) - return; - - QBS_CHECK(value->type() == Value::JSSourceValueType); - - if (decl.isScalar()) { - QBS_CHECK(!globalVal->expired(productItem)); - QBS_CHECK(!value->expired(productItem)); - if (compareValuePriorities(productItem, globalVal, value) < 0) { - value->setCandidates(globalVal->candidates()); - globalVal->setCandidates({}); - value->addCandidate(globalVal); - globalInstance->setProperty(decl.name(), value); - } else { - globalVal->addCandidate(value); - } - } else { - if (const ValuePtr &newChainStart = mergeListValues(productItem, globalVal, value); - newChainStart != globalVal) { - globalInstance->setProperty(decl.name(), newChainStart); - } - } -} - -bool ModulePropertyMerger::Private::doFinalMerge(const Item *productItem, Item *moduleItem) -{ - if (!moduleItem->isPresentModule()) - return false; - bool mustInvalidateCache = false; - for (auto it = moduleItem->properties().begin(); it != moduleItem->properties().end(); ++it) { - if (doFinalMerge(productItem, moduleItem->propertyDeclaration(it.key()), it.value())) - mustInvalidateCache = true; - } - return mustInvalidateCache; -} - -bool ModulePropertyMerger::Private::doFinalMerge( - const Item *productItem, const PropertyDeclaration &propertyDecl, ValuePtr &propertyValue) -{ - if (propertyValue->type() == Value::VariantValueType) { - QBS_CHECK(!propertyValue->next()); - return false; - } - if (!propertyDecl.isValid()) - return false; // Caught later by dedicated checker. - propertyValue->resetPriority(); - if (propertyDecl.isScalar()) { - if (propertyValue->candidates().empty()) - return false; - std::pair<int, std::vector<ValuePtr>> candidatesWithHighestPrio; - candidatesWithHighestPrio.first = propertyValue->priority(productItem); - candidatesWithHighestPrio.second.push_back(propertyValue); - for (const ValuePtr &v : propertyValue->candidates()) { - const int prio = v->priority(productItem); - if (prio < candidatesWithHighestPrio.first) - continue; - if (prio > candidatesWithHighestPrio.first) { - candidatesWithHighestPrio.first = prio; - candidatesWithHighestPrio.second = {v}; - continue; - } - candidatesWithHighestPrio.second.push_back(v); - } - ValuePtr chosenValue = candidatesWithHighestPrio.second.front(); - if (int(candidatesWithHighestPrio.second.size()) > 1) { - ErrorInfo error(Tr::tr("Conflicting scalar values for property '%1'.") - .arg(propertyDecl.name())); - error.append({}, chosenValue->location()); - QBS_CHECK(chosenValue->type() == Value::JSSourceValueType); - QStringView sourcCode = static_cast<JSSourceValue *>( - chosenValue.get())->sourceCode(); - for (int i = 1; i < int(candidatesWithHighestPrio.second.size()); ++i) { - const ValuePtr &v = candidatesWithHighestPrio.second.at(i); - QBS_CHECK(v->type() == Value::JSSourceValueType); - - // Note that this is a bit silly: The source code could still evaluate to - // different values in the end. - if (static_cast<JSSourceValue *>(v.get())->sourceCode() != sourcCode) - error.append({}, v->location()); - } - if (error.items().size() > 2) - logger.printWarning(error); - } - - if (propertyValue == chosenValue) - return false; - propertyValue = chosenValue; - return true; - } - if (!propertyValue->next()) - return false; - std::vector<ValuePtr> singleValuesBefore; - for (ValuePtr current = propertyValue; current;) { - singleValuesBefore.push_back(current); - const ValuePtr next = current->next(); - if (next) - current->setNext({}); - current = next; - } - ValuePtr newValue; - for (const ValuePtr &v : singleValuesBefore) - newValue = mergeListValues(productItem, newValue, v); - std::vector<ValuePtr> singleValuesAfter; - for (ValuePtr current = propertyValue; current; current = current->next()) - singleValuesAfter.push_back(current); - propertyValue = newValue; - return singleValuesBefore != singleValuesAfter; -} - -} // namespace qbs::Internal |