diff options
-rw-r--r-- | src/lib/corelib/language/itemreaderastvisitor.cpp | 38 | ||||
-rw-r--r-- | src/lib/corelib/language/itemreadervisitorstate.cpp | 10 | ||||
-rw-r--r-- | src/lib/corelib/language/itemreadervisitorstate.h | 4 | ||||
-rw-r--r-- | tests/auto/language/testdata/idusage_group.qbs | 5 | ||||
-rw-r--r-- | tests/auto/language/testdata/idusage_group2.qbs | 5 | ||||
-rw-r--r-- | tests/auto/language/testdata/idusagebase.qbs | 12 | ||||
-rw-r--r-- | tests/auto/language/testdata/idusagebasebase.qbs | 5 | ||||
-rw-r--r-- | tests/auto/language/tst_language.cpp | 32 |
8 files changed, 100 insertions, 11 deletions
diff --git a/src/lib/corelib/language/itemreaderastvisitor.cpp b/src/lib/corelib/language/itemreaderastvisitor.cpp index 86274b1c2..d6b89a2d5 100644 --- a/src/lib/corelib/language/itemreaderastvisitor.cpp +++ b/src/lib/corelib/language/itemreaderastvisitor.cpp @@ -59,6 +59,8 @@ #include <tools/stringconstants.h> #include <logging/translator.h> +#include <algorithm> + using namespace QbsQmlJS; namespace qbs { @@ -81,11 +83,29 @@ bool ItemReaderASTVisitor::visit(AST::UiImportList *uiImportList) return false; } +static ItemValuePtr findItemProperty(const Item *container, const Item *item) +{ + ItemValuePtr itemValue; + const auto &srcprops = container->properties(); + auto it = std::find_if(srcprops.begin(), srcprops.end(), [item] (const ValuePtr &v) { + return v->type() == Value::ItemValueType + && std::static_pointer_cast<ItemValue>(v)->item() == item; + }); + if (it != srcprops.end()) + itemValue = std::static_pointer_cast<ItemValue>(it.value()); + return itemValue; +} + bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) { const QString typeName = ast->qualifiedTypeNameId->name.toString(); const CodeLocation itemLocation = toCodeLocation(ast->qualifiedTypeNameId->identifierToken); const Item *baseItem = nullptr; + Item *mostDerivingItem = nullptr; + + Item *item = Item::create(m_itemPool, ItemType::Unknown); + item->setFile(m_file); + item->setLocation(itemLocation); // Inheritance resolving, part 1: Find out our actual type name (needed for setting // up children and alternatives). @@ -93,7 +113,13 @@ bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) const QString baseTypeFileName = m_typeNameToFile.value(fullTypeName); ItemType itemType; if (!baseTypeFileName.isEmpty()) { + const bool isMostDerivingItem = (m_visitorState.mostDerivingItem() == nullptr); + if (isMostDerivingItem) + m_visitorState.setMostDerivingItem(item); + mostDerivingItem = m_visitorState.mostDerivingItem(); baseItem = m_visitorState.readFile(baseTypeFileName, m_file->searchPaths(), m_itemPool); + if (isMostDerivingItem) + m_visitorState.setMostDerivingItem(nullptr); QBS_CHECK(baseItem->type() <= ItemType::LastActualItem); itemType = baseItem->type(); } else { @@ -107,9 +133,7 @@ bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) itemType = ItemType::PropertiesInSubProject; } - Item *item = Item::create(m_itemPool, itemType); - item->setFile(m_file); - item->setLocation(itemLocation); + item->m_type = itemType; if (m_item) Item::addChild(m_item, item); // Add this item to the children of the parent item. @@ -117,9 +141,12 @@ bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) m_item = item; // This is the root item. if (ast->initializer) { + Item *mdi = m_visitorState.mostDerivingItem(); + m_visitorState.setMostDerivingItem(nullptr); qSwap(m_item, item); ast->initializer->accept(this); qSwap(m_item, item); + m_visitorState.setMostDerivingItem(mdi); } ASTPropertiesItemHandler(item).handlePropertiesItems(); @@ -132,6 +159,11 @@ bool ItemReaderASTVisitor::visit(AST::UiObjectDefinition *ast) // ### Do we want to turn off this feature? It's QMLish but kind of strange. item->file()->ensureIdScope(m_itemPool); baseItem->file()->idScope()->setPrototype(item->file()->idScope()); + + // Replace the base item with the most deriving item. + ItemValuePtr baseItemIdValue = findItemProperty(baseItem->file()->idScope(), baseItem); + if (baseItemIdValue) + baseItemIdValue->setItem(mostDerivingItem); } } else { // Only the item at the top of the inheritance chain is a built-in item. diff --git a/src/lib/corelib/language/itemreadervisitorstate.cpp b/src/lib/corelib/language/itemreadervisitorstate.cpp index a48f081ff..ca6ba2e12 100644 --- a/src/lib/corelib/language/itemreadervisitorstate.cpp +++ b/src/lib/corelib/language/itemreadervisitorstate.cpp @@ -186,6 +186,16 @@ bool ItemReaderVisitorState::findDirectoryEntries(const QString &dirPath, QStrin return true; } +Item *ItemReaderVisitorState::mostDerivingItem() const +{ + return m_mostDerivingItem; +} + +void ItemReaderVisitorState::setMostDerivingItem(Item *item) +{ + m_mostDerivingItem = item; +} + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/language/itemreadervisitorstate.h b/src/lib/corelib/language/itemreadervisitorstate.h index a72d5fe3a..0eab34dbb 100644 --- a/src/lib/corelib/language/itemreadervisitorstate.h +++ b/src/lib/corelib/language/itemreadervisitorstate.h @@ -64,10 +64,14 @@ public: void cacheDirectoryEntries(const QString &dirPath, const QStringList &entries); bool findDirectoryEntries(const QString &dirPath, QStringList *entries) const; + Item *mostDerivingItem() const; + void setMostDerivingItem(Item *item); + private: Logger &m_logger; Set<QString> m_filesRead; QHash<QString, QStringList> m_directoryEntries; + Item *m_mostDerivingItem = nullptr; class ASTCache; ASTCache * const m_astCache; diff --git a/tests/auto/language/testdata/idusage_group.qbs b/tests/auto/language/testdata/idusage_group.qbs new file mode 100644 index 000000000..7da7984f8 --- /dev/null +++ b/tests/auto/language/testdata/idusage_group.qbs @@ -0,0 +1,5 @@ +Group { + id: baseGroup + name: "base" + prefix: baseGroup.name +} diff --git a/tests/auto/language/testdata/idusage_group2.qbs b/tests/auto/language/testdata/idusage_group2.qbs new file mode 100644 index 000000000..697e21c30 --- /dev/null +++ b/tests/auto/language/testdata/idusage_group2.qbs @@ -0,0 +1,5 @@ +import "idusage_group.qbs" as MyGroup + +MyGroup { + name: "between the hammer and the anvil" +} diff --git a/tests/auto/language/testdata/idusagebase.qbs b/tests/auto/language/testdata/idusagebase.qbs index 0606ded16..e7424d648 100644 --- a/tests/auto/language/testdata/idusagebase.qbs +++ b/tests/auto/language/testdata/idusagebase.qbs @@ -1,6 +1,16 @@ -Product { +import "idusagebasebase.qbs" as DeriveMeCrazy +import "idusage_group.qbs" as MyGroup +import "idusage_group2.qbs" as MyGroup2 + +DeriveMeCrazy { id: baseProduct property int nr: theProject.initialNr + 1 name: "product1_" + nr property string productName: baseProduct.name + MyGroup { + name: "group in base product" + } + MyGroup2 { + name: "another group in base product" + } } diff --git a/tests/auto/language/testdata/idusagebasebase.qbs b/tests/auto/language/testdata/idusagebasebase.qbs new file mode 100644 index 000000000..addc6b9fd --- /dev/null +++ b/tests/auto/language/testdata/idusagebasebase.qbs @@ -0,0 +1,5 @@ +Product { + id: baseBaseProduct + name: "ace of base" + property string productNameInBaseOfBase: baseBaseProduct.name +} diff --git a/tests/auto/language/tst_language.cpp b/tests/auto/language/tst_language.cpp index ff7fb77ba..8124cc2ac 100644 --- a/tests/auto/language/tst_language.cpp +++ b/tests/auto/language/tst_language.cpp @@ -109,13 +109,22 @@ QHash<QString, ResolvedProductPtr> TestLanguage::productsFromProject(ResolvedPro return result; } +template <typename C> +typename C::value_type findByName(const C &container, const QString &name) +{ + auto endIt = std::end(container); + auto it = std::find_if(std::begin(container), endIt, + [&name] (const typename C::value_type &thing) { + return thing->name == name; + }); + if (it != endIt) + return *it; + return typename C::value_type(); +} + ResolvedModuleConstPtr TestLanguage::findModuleByName(ResolvedProductPtr product, const QString &name) { - const auto modules = product->modules; - for (const ResolvedModuleConstPtr &module : modules) - if (module->name == name) - return module; - return ResolvedModuleConstPtr(); + return findByName(product->modules, name); } QVariant TestLanguage::productPropertyValue(ResolvedProductPtr product, QString propertyName) @@ -1221,8 +1230,17 @@ void TestLanguage::idUsage() QVERIFY(products.contains("product3_3")); ResolvedProductPtr product4 = products.value("product4_4"); QVERIFY(!!product4); - QEXPECT_FAIL("", "QBS-1016", Continue); - QCOMPARE(product4->productProperties.value("productName").toString(), product4->name); + auto product4Property = [&product4] (const char *name) { + return product4->productProperties.value(QString::fromUtf8(name)).toString(); + }; + QCOMPARE(product4Property("productName"), product4->name); + QCOMPARE(product4Property("productNameInBaseOfBase"), product4->name); + GroupPtr group = findByName(product4->groups, "group in base product"); + QVERIFY(!!group); + QCOMPARE(qPrintable(group->prefix), "group in base product"); + group = findByName(product4->groups, "another group in base product"); + QVERIFY(!!group); + QCOMPARE(qPrintable(group->prefix), "another group in base product"); ResolvedProductPtr product5 = products.value("product5"); QVERIFY(!!product5); QCOMPARE(product5->moduleProperties->moduleProperty("deepdummy.deep.moat", "zort") |