aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/lib/corelib/language/itemreaderastvisitor.cpp38
-rw-r--r--src/lib/corelib/language/itemreadervisitorstate.cpp10
-rw-r--r--src/lib/corelib/language/itemreadervisitorstate.h4
-rw-r--r--tests/auto/language/testdata/idusage_group.qbs5
-rw-r--r--tests/auto/language/testdata/idusage_group2.qbs5
-rw-r--r--tests/auto/language/testdata/idusagebase.qbs12
-rw-r--r--tests/auto/language/testdata/idusagebasebase.qbs5
-rw-r--r--tests/auto/language/tst_language.cpp32
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")