diff options
author | Joerg Bornemann <joerg.bornemann@theqtcompany.com> | 2015-07-23 11:55:11 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@theqtcompany.com> | 2015-08-04 14:47:02 +0000 |
commit | 8c5e63fae7509b6dcc8a3d4387e5d27093ede7fc (patch) | |
tree | f0a844ff4f927ea37f471c7108186d705da44c1e | |
parent | 6cc4b9d6af6ed169cdb05a3925e50d353ab8c8a9 (diff) | |
download | qbs-8c5e63fae7509b6dcc8a3d4387e5d27093ede7fc.tar.gz |
Make it possible to overwrite properties conditionally.
If a product or higher-level module wants to set the property of a
(different) module only if some condition is fulfilled and leave it
unchanged otherwise, it would currently need to duplicate the value
from the module prototype. Obviously, this is not feasible for anything
but the most trivial definitions, and even then it easily introduces
maintenance problems.
Change-Id: If33c93a25dc84603fe95704e8815aa6e3aa1e0e4
Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
-rw-r--r-- | doc/reference/items/module.qdoc | 15 | ||||
-rw-r--r-- | src/lib/corelib/language/evaluatorscriptclass.cpp | 10 | ||||
-rw-r--r-- | src/lib/corelib/language/itemreaderastvisitor.cpp | 5 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/defaultvalue/egon.qbs | 14 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/defaultvalue/modules/higher/higher.qbs | 7 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/defaultvalue/modules/lower/lower.qbs | 7 | ||||
-rw-r--r-- | src/lib/corelib/language/testdata/defaultvalue/test.txt | 0 | ||||
-rw-r--r-- | src/lib/corelib/language/tst_language.cpp | 51 | ||||
-rw-r--r-- | src/lib/corelib/language/tst_language.h | 2 | ||||
-rw-r--r-- | src/lib/corelib/language/value.h | 2 | ||||
-rw-r--r-- | src/lib/qtprofilesetup/templates/core.qbs | 1 |
11 files changed, 112 insertions, 2 deletions
diff --git a/doc/reference/items/module.qdoc b/doc/reference/items/module.qdoc index 4a6e38678..343790f47 100644 --- a/doc/reference/items/module.qdoc +++ b/doc/reference/items/module.qdoc @@ -118,6 +118,20 @@ } \endcode + \section2 \c original + This is the value of the property in the module itself (possibly overridden from a profile or + the command line). Use it to set a module property conditionally: + \code + Module { // This is mymodule + property string aProperty: "z" + } + ---------- + Product { + Depends { name: "mymodule" } + Depends { name: "myothermodule" } + mymodule.aProperty: myothermodule.anotherProperty === "x" ? "y" : original // => "y" if myothermodule.anotherProperty is "x", "z" otherwise + \endcode + \section2 \c outer This value is used in nested items, where it refers to the value of the respective property in the surrounding item. It is often encountered in \l{Group Item}{groups}: @@ -133,6 +147,7 @@ } \endcode + \section1 Module Properties \table diff --git a/src/lib/corelib/language/evaluatorscriptclass.cpp b/src/lib/corelib/language/evaluatorscriptclass.cpp index e9e6d8d36..e0dd5a525 100644 --- a/src/lib/corelib/language/evaluatorscriptclass.cpp +++ b/src/lib/corelib/language/evaluatorscriptclass.cpp @@ -215,6 +215,16 @@ private: if (value->sourceUsesOuter() && outerItem) setupConvenienceProperty(QLatin1String("outer"), &extraScope, data->evaluator->property(outerItem, *propertyName)); + if (value->sourceUsesOriginal()) { + const Item *item = itemOfProperty; + while (item->isModuleInstance()) + item = item->prototype(); + QScriptValue originalValue; + SVConverter converter(scriptClass, object, item->property(*propertyName), item, + propertyName, data, &originalValue, sourceValueStack); + converter.start(); + setupConvenienceProperty(QLatin1String("original"), &extraScope, originalValue); + } pushScope(data->evaluator->fileScope(value->file())); pushItemScopes(data->item); diff --git a/src/lib/corelib/language/itemreaderastvisitor.cpp b/src/lib/corelib/language/itemreaderastvisitor.cpp index 0fc4696c8..0815ef01a 100644 --- a/src/lib/corelib/language/itemreaderastvisitor.cpp +++ b/src/lib/corelib/language/itemreaderastvisitor.cpp @@ -463,15 +463,18 @@ bool ItemReaderASTVisitor::visitStatement(AST::Statement *statement) m_sourceValue->setLocation(statement->firstSourceLocation().startLine, statement->firstSourceLocation().startColumn); - bool usesBase, usesOuter; + bool usesBase, usesOuter, usesOriginal; IdentifierSearch idsearch; idsearch.add(QLatin1String("base"), &usesBase); idsearch.add(QLatin1String("outer"), &usesOuter); + idsearch.add(QLatin1String("original"), &usesOriginal); idsearch.start(statement); if (usesBase) m_sourceValue->m_flags |= JSSourceValue::SourceUsesBase; if (usesOuter) m_sourceValue->m_flags |= JSSourceValue::SourceUsesOuter; + if (usesOriginal) + m_sourceValue->m_flags |= JSSourceValue::SourceUsesOriginal; return false; } diff --git a/src/lib/corelib/language/testdata/defaultvalue/egon.qbs b/src/lib/corelib/language/testdata/defaultvalue/egon.qbs new file mode 100644 index 000000000..7b254b0c8 --- /dev/null +++ b/src/lib/corelib/language/testdata/defaultvalue/egon.qbs @@ -0,0 +1,14 @@ +import qbs + +Project { + Product { + name: "dep" + Export { Depends { name: "higher" } } + } + + Product { + name: "egon" + Depends { name: "dep" } + lower.prop1: "blubb" + } +} diff --git a/src/lib/corelib/language/testdata/defaultvalue/modules/higher/higher.qbs b/src/lib/corelib/language/testdata/defaultvalue/modules/higher/higher.qbs new file mode 100644 index 000000000..9894f80cf --- /dev/null +++ b/src/lib/corelib/language/testdata/defaultvalue/modules/higher/higher.qbs @@ -0,0 +1,7 @@ +import qbs + +Module { + Depends { name: "lower" } + lower.prop2: lower.prop1 === "egon" ? "withEgon" : original + lower.listProp: lower.prop1 === "egon" ? ["egon"] : original +} diff --git a/src/lib/corelib/language/testdata/defaultvalue/modules/lower/lower.qbs b/src/lib/corelib/language/testdata/defaultvalue/modules/lower/lower.qbs new file mode 100644 index 000000000..0540185e9 --- /dev/null +++ b/src/lib/corelib/language/testdata/defaultvalue/modules/lower/lower.qbs @@ -0,0 +1,7 @@ +import qbs + +Module { + property string prop1 + property string prop2: prop1 === "blubb" ? "withBlubb" : "withoutBlubb" + property stringList listProp: prop1 === "blubb" ? ["blubb", "other"] : ["other"] +} diff --git a/src/lib/corelib/language/testdata/defaultvalue/test.txt b/src/lib/corelib/language/testdata/defaultvalue/test.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/lib/corelib/language/testdata/defaultvalue/test.txt diff --git a/src/lib/corelib/language/tst_language.cpp b/src/lib/corelib/language/tst_language.cpp index c227f1b83..8dd911ff3 100644 --- a/src/lib/corelib/language/tst_language.cpp +++ b/src/lib/corelib/language/tst_language.cpp @@ -354,6 +354,55 @@ void qbs::Internal::TestLanguage::dependencyOnAllProfiles() QCOMPARE(exceptionCaught, false); } +void TestLanguage::defaultValue() +{ + bool exceptionCaught = false; + try { + SetupProjectParameters params = defaultParameters; + params.setProjectFilePath(testProject("defaultvalue/egon.qbs")); + QFETCH(QString, prop1Value); + QVariantMap overridden; + if (!prop1Value.isEmpty()) + overridden.insert("lower.prop1", prop1Value); + params.setOverriddenValues(overridden); + TopLevelProjectPtr project = loader->loadProject(params); + QVERIFY(project); + QHash<QString, ResolvedProductPtr> products = productsFromProject(project); + QCOMPARE(products.count(), 2); + const ResolvedProductPtr product = products.value("egon"); + QVERIFY(product); + QStringList propertyName = QStringList() << "modules" << "lower" << "prop2"; + QVariant propertyValue = getConfigProperty(product->moduleProperties->value(), propertyName); + QFETCH(QVariant, expectedProp2Value); + QCOMPARE(propertyValue, expectedProp2Value); + propertyName = QStringList() << "modules" << "lower" << "listProp"; + propertyValue = getConfigProperty(product->moduleProperties->value(), propertyName); + QFETCH(QVariant, expectedListPropValue); + QEXPECT_FAIL("controlling property not overwritten", "QBS-845", Continue); + QCOMPARE(propertyValue.toStringList(), expectedListPropValue.toStringList()); + } + catch (const ErrorInfo &e) { + exceptionCaught = true; + qDebug() << e.toString(); + } + QCOMPARE(exceptionCaught, false); +} + +void TestLanguage::defaultValue_data() +{ + QTest::addColumn<QString>("prop1Value"); + QTest::addColumn<QVariant>("expectedProp2Value"); + QTest::addColumn<QVariant>("expectedListPropValue"); + QTest::newRow("controlling property with random value") << "random" << QVariant("withoutBlubb") + << QVariant(QStringList({"other", "other"})); + QTest::newRow("controlling property with blubb value") << "blubb" << QVariant("withBlubb") + << QVariant(QStringList({"blubb", "other", "blubb", "other"})); + QTest::newRow("controlling property with egon value") << "egon" << QVariant("withEgon") + << QVariant(QStringList({"egon", "other"})); + QTest::newRow("controlling property not overwritten") << "" << QVariant("withBlubb") + << QVariant(QStringList({"blubb", "other", "blubb", "other"})); +} + void TestLanguage::environmentVariable() { bool exceptionCaught = false; @@ -998,7 +1047,7 @@ void TestLanguage::moduleProperties() QStringList valueStrings; foreach (const QVariant &v, values) valueStrings += v.toString(); - QEXPECT_FAIL("list_property_depending_on_overridden_property", "QBS_845", Continue); + QEXPECT_FAIL("list_property_depending_on_overridden_property", "QBS-845", Continue); QCOMPARE(valueStrings, expectedValues); } diff --git a/src/lib/corelib/language/tst_language.h b/src/lib/corelib/language/tst_language.h index 624f5428b..863f2b7b4 100644 --- a/src/lib/corelib/language/tst_language.h +++ b/src/lib/corelib/language/tst_language.h @@ -106,6 +106,8 @@ private slots: void profileValuesAndOverriddenValues(); void propertiesBlocks_data(); void propertiesBlocks(); + void defaultValue(); + void defaultValue_data(); void qualifiedId(); void recursiveProductDependencies(); void rfc1034Identifier(); diff --git a/src/lib/corelib/language/value.h b/src/lib/corelib/language/value.h index 8f17f0be9..7dbbdd9bc 100644 --- a/src/lib/corelib/language/value.h +++ b/src/lib/corelib/language/value.h @@ -90,6 +90,7 @@ class JSSourceValue : public Value NoFlags = 0x00, SourceUsesBase = 0x01, SourceUsesOuter = 0x02, + SourceUsesOriginal = 0x04, HasFunctionForm = 0x08 }; Q_DECLARE_FLAGS(Flags, Flag) @@ -116,6 +117,7 @@ public: void setSourceUsesBaseFlag() { m_flags |= SourceUsesBase; } bool sourceUsesBase() const { return m_flags.testFlag(SourceUsesBase); } bool sourceUsesOuter() const { return m_flags.testFlag(SourceUsesOuter); } + bool sourceUsesOriginal() const { return m_flags.testFlag(SourceUsesOriginal); } bool isInExportItem() const { return m_exportScope; } bool hasFunctionForm() const { return m_flags.testFlag(HasFunctionForm); } void setHasFunctionForm(bool b); diff --git a/src/lib/qtprofilesetup/templates/core.qbs b/src/lib/qtprofilesetup/templates/core.qbs index 844a58784..8bec90675 100644 --- a/src/lib/qtprofilesetup/templates/core.qbs +++ b/src/lib/qtprofilesetup/templates/core.qbs @@ -144,6 +144,7 @@ Module { if (qbs.targetOS.contains('darwin') && qbs.toolchain.contains('clang') && config.contains('c++11')) return "libc++"; + return original; } additionalProductTypes: ["qm"] |