aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/language
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2017-07-13 12:00:18 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2018-03-14 08:52:50 +0000
commit149e20aca1e401ba18bbae602df2caa7dc68c493 (patch)
tree29b0b5a270696040b5b8c668834c2e6929ec621f /src/lib/corelib/language
parentd0f29502e0d4f3e21fbe0f0b7b56c62b4f85fde3 (diff)
Provide rules with information about the content of Export items
The product variable gets a new property "exports" that provides a "dependencies" array as well as property values the same way that the product variable itself does, but for exported dependencies and properties, respectively. In addition, meta data about these properties is provided via a "properties" array, and structural information can be retrieved via "childItems". This data is intended to be used by modules creating interface files from products. Task-number: QBS-268 Change-Id: I2bb106e1ca1b18abbd6fe60411bc81bda9ee35e7 Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
Diffstat (limited to 'src/lib/corelib/language')
-rw-r--r--src/lib/corelib/language/astimportshandler.cpp2
-rw-r--r--src/lib/corelib/language/builtindeclarations.cpp2
-rw-r--r--src/lib/corelib/language/evaluator.h2
-rw-r--r--src/lib/corelib/language/forward_decls.h6
-rw-r--r--src/lib/corelib/language/language.cpp58
-rw-r--r--src/lib/corelib/language/language.h85
-rw-r--r--src/lib/corelib/language/moduleloader.cpp42
-rw-r--r--src/lib/corelib/language/moduleloader.h2
-rw-r--r--src/lib/corelib/language/preparescriptobserver.cpp5
-rw-r--r--src/lib/corelib/language/preparescriptobserver.h7
-rw-r--r--src/lib/corelib/language/projectresolver.cpp482
-rw-r--r--src/lib/corelib/language/projectresolver.h23
-rw-r--r--src/lib/corelib/language/propertydeclaration.cpp7
-rw-r--r--src/lib/corelib/language/propertydeclaration.h1
-rw-r--r--src/lib/corelib/language/scriptengine.h5
15 files changed, 663 insertions, 66 deletions
diff --git a/src/lib/corelib/language/astimportshandler.cpp b/src/lib/corelib/language/astimportshandler.cpp
index 36194fd8c..d72f44542 100644
--- a/src/lib/corelib/language/astimportshandler.cpp
+++ b/src/lib/corelib/language/astimportshandler.cpp
@@ -185,7 +185,7 @@ void ASTImportsHandler::handleImport(const QbsQmlJS::AST::UiImport *import)
for (const QString &searchPath : m_file->searchPaths()) {
const QFileInfo fi(FileInfo::resolvePath(
FileInfo::resolvePath(searchPath,
- QStringLiteral("imports")),
+ StringConstants::importsDir()),
importPath));
if (fi.isDir()) {
// ### versioning, qbsdir file, etc.
diff --git a/src/lib/corelib/language/builtindeclarations.cpp b/src/lib/corelib/language/builtindeclarations.cpp
index 686b887e1..e3f4199e3 100644
--- a/src/lib/corelib/language/builtindeclarations.cpp
+++ b/src/lib/corelib/language/builtindeclarations.cpp
@@ -248,6 +248,8 @@ void BuiltinDeclarations::addDependsItem()
void BuiltinDeclarations::addExportItem()
{
ItemDeclaration item = moduleLikeItem(ItemType::Export);
+ item << PropertyDeclaration(StringConstants::prefixMappingProperty(),
+ PropertyDeclaration::Variant);
auto allowedChildTypes = item.allowedChildTypes();
allowedChildTypes.insert(ItemType::Parameters);
allowedChildTypes.insert(ItemType::Properties);
diff --git a/src/lib/corelib/language/evaluator.h b/src/lib/corelib/language/evaluator.h
index ddb4940af..0fd4003d8 100644
--- a/src/lib/corelib/language/evaluator.h
+++ b/src/lib/corelib/language/evaluator.h
@@ -102,11 +102,11 @@ public:
void setPathPropertiesBaseDir(const QString &dirPath);
void clearPathPropertiesBaseDir();
+ bool isNonDefaultValue(const Item *item, const QString &name) const;
private:
void onItemPropertyChanged(Item *item);
bool evaluateProperty(QScriptValue *result, const Item *item, const QString &name,
bool *propertyWasSet);
- bool isNonDefaultValue(const Item *item, const QString &name) const;
ScriptEngine *m_scriptEngine;
EvaluatorScriptClass *m_scriptClass;
diff --git a/src/lib/corelib/language/forward_decls.h b/src/lib/corelib/language/forward_decls.h
index fc51c7993..5ce333ce9 100644
--- a/src/lib/corelib/language/forward_decls.h
+++ b/src/lib/corelib/language/forward_decls.h
@@ -131,7 +131,13 @@ class ArtifactProperties;
typedef std::shared_ptr<ArtifactProperties> ArtifactPropertiesPtr;
typedef std::shared_ptr<const ArtifactProperties> ArtifactPropertiesConstPtr;
+class ExportedItem;
+using ExportedItemPtr = std::shared_ptr<ExportedItem>;
+class ExportedModule;
+class ExportedModuleDependency;
+class ExportedProperty;
class PersistentPool;
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp
index 43f44bf98..cc0da3d8a 100644
--- a/src/lib/corelib/language/language.cpp
+++ b/src/lib/corelib/language/language.cpp
@@ -940,5 +940,63 @@ bool operator==(const PrivateScriptFunction &a, const PrivateScriptFunction &b)
return equals(a.m_sharedData.get(), b.m_sharedData.get());
}
+bool operator==(const ExportedProperty &p1, const ExportedProperty &p2)
+{
+ return p1.fullName == p2.fullName
+ && p1.type == p2.type
+ && p1.sourceCode == p2.sourceCode
+ && p1.isBuiltin == p2.isBuiltin;
+}
+
+bool operator==(const ExportedModuleDependency &d1, const ExportedModuleDependency &d2)
+{
+ return d1.name == d2.name && d1.moduleProperties == d2.moduleProperties;
+}
+
+bool equals(const std::vector<ExportedItemPtr> &l1, const std::vector<ExportedItemPtr> &l2)
+{
+ static const auto cmp = [](const ExportedItemPtr &p1, const ExportedItemPtr &p2) {
+ return *p1 == *p2;
+ };
+ return l1.size() == l2.size() && std::equal(l1.cbegin(), l1.cend(), l2.cbegin(), cmp);
+}
+
+bool operator==(const ExportedItem &i1, const ExportedItem &i2)
+{
+ return i1.name == i2.name
+ && i1.properties == i2.properties
+ && equals(i1.children, i2.children);
+}
+
+bool operator==(const ExportedModule &m1, const ExportedModule &m2)
+{
+ static const auto cmpProductsByName = [](
+ const ResolvedProductConstPtr &p1,
+ const ResolvedProductConstPtr &p2) {
+ return p1->name == p2->name;
+ };
+ static const auto depMapsEqual = [](const QHash<ResolvedProductConstPtr, QVariantMap> &m1,
+ const QHash<ResolvedProductConstPtr, QVariantMap> &m2) {
+ if (m1.size() != m2.size())
+ return false;
+ for (auto it1 = m1.cbegin(), it2 = m2.cbegin(); it1 != m1.cend(); ++it1, ++it2) {
+ if (it1.key()->name != it2.key()->name)
+ return false;
+ if (it1.value() != it2.value())
+ return false;
+ }
+ return true;
+ };
+ return m1.propertyValues == m2.propertyValues
+ && m1.modulePropertyValues == m2.modulePropertyValues
+ && equals(m1.children, m2.children)
+ && m1.m_properties == m2.m_properties
+ && m1.importStatements == m2.importStatements
+ && m1.productDependencies.size() == m2.productDependencies.size()
+ && std::equal(m1.productDependencies.cbegin(), m1.productDependencies.cend(),
+ m2.productDependencies.cbegin(), cmpProductsByName)
+ && depMapsEqual(m1.dependencyParameters, m2.dependencyParameters);
+}
+
} // namespace Internal
} // namespace qbs
diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h
index 0b44f4253..2ec152221 100644
--- a/src/lib/corelib/language/language.h
+++ b/src/lib/corelib/language/language.h
@@ -43,6 +43,7 @@
#include "filetags.h"
#include "forward_decls.h"
#include "jsimports.h"
+#include "propertydeclaration.h"
#include "resolvedfilecontext.h"
#include <buildgraph/forward_decls.h>
@@ -467,6 +468,86 @@ private:
{}
};
+class ExportedProperty
+{
+public:
+ template<PersistentPool::OpType opType> void completeSerializationOp(PersistentPool &pool)
+ {
+ pool.serializationOp<opType>(fullName, type, sourceCode, isBuiltin);
+ }
+
+ QString fullName;
+ PropertyDeclaration::Type type;
+ QString sourceCode;
+ bool isBuiltin = false;
+};
+
+bool operator==(const ExportedProperty &p1, const ExportedProperty &p2);
+inline bool operator!=(const ExportedProperty &p1, const ExportedProperty &p2)
+{
+ return !(p1 == p2);
+}
+
+class ExportedItem
+{
+public:
+ template<PersistentPool::OpType opType> void completeSerializationOp(PersistentPool &pool)
+ {
+ pool.serializationOp<opType>(name, properties, children);
+ }
+
+ static ExportedItemPtr create() { return std::make_shared<ExportedItem>(); }
+
+ QString name;
+ std::vector<ExportedProperty> properties;
+ std::vector<ExportedItemPtr> children;
+};
+
+bool equals(const std::vector<ExportedItemPtr> &l1, const std::vector<ExportedItemPtr> &l2);
+bool operator==(const ExportedItem &i1, const ExportedItem &i2);
+inline bool operator!=(const ExportedItem &i1, const ExportedItem &i2) { return !(i1 == i2); }
+
+class ExportedModuleDependency
+{
+public:
+ template<PersistentPool::OpType opType> void completeSerializationOp(PersistentPool &pool)
+ {
+ pool.serializationOp<opType>(name, moduleProperties);
+ };
+
+ QString name;
+ QVariantMap moduleProperties;
+};
+
+bool operator==(const ExportedModuleDependency &d1, const ExportedModuleDependency &d2);
+inline bool operator!=(const ExportedModuleDependency &d1, const ExportedModuleDependency &d2)
+{
+ return !(d1 == d2);
+}
+
+class ExportedModule
+{
+public:
+ template<PersistentPool::OpType opType> void completeSerializationOp(PersistentPool &pool)
+ {
+ pool.serializationOp<opType>(propertyValues, modulePropertyValues, children,
+ productDependencies, moduleDependencies, m_properties,
+ dependencyParameters, importStatements);
+ };
+
+ QVariantMap propertyValues;
+ QVariantMap modulePropertyValues;
+ std::vector<ExportedItemPtr> children;
+ Set<ResolvedProductPtr> productDependencies;
+ std::vector<ExportedModuleDependency> moduleDependencies;
+ std::vector<ExportedProperty> m_properties;
+ QHash<ResolvedProductConstPtr, QVariantMap> dependencyParameters;
+ QStringList importStatements;
+};
+
+bool operator==(const ExportedModule &m1, const ExportedModule &m2);
+inline bool operator!=(const ExportedModule &m1, const ExportedModule &m2) { return !(m1 == m2); }
+
class TopLevelProject;
class ScriptEngine;
@@ -502,6 +583,8 @@ public:
QStringList missingSourceFiles;
std::unique_ptr<ProductBuildData> buildData;
+ ExportedModule exportedModule;
+
QProcessEnvironment buildEnvironment; // must not be saved
QProcessEnvironment runEnvironment; // must not be saved
@@ -551,7 +634,7 @@ private:
missingSourceFiles, location, productProperties,
moduleProperties, rules, dependencies, dependencyParameters,
fileTaggers, modules, moduleParameters, scanners, groups,
- artifactProperties, probes, buildData);
+ artifactProperties, probes, exportedModule, buildData);
}
QHash<QString, QString> m_executablePathCache;
diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp
index 6d005c676..20a225918 100644
--- a/src/lib/corelib/language/moduleloader.cpp
+++ b/src/lib/corelib/language/moduleloader.cpp
@@ -81,6 +81,8 @@
namespace qbs {
namespace Internal {
+static QString shadowProductPrefix() { return QStringLiteral("__shadow__"); }
+
static QString multiplexConfigurationIdPropertyInternal()
{
return QStringLiteral("__multiplexConfigIdForModulePrototypes");
@@ -915,14 +917,26 @@ void ModuleLoader::adjustDependenciesForMultiplexing(const ModuleLoader::Product
// 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.
+ // (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)
continue;
QStringList multiplexIds;
+ const bool isShadowProduct = product.name.startsWith(shadowProductPrefix())
+ && product.name.mid(shadowProductPrefix().size()) == name;
for (const ProductContext *dependency : dependencies) {
+ 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) { // (2)
const ValuePtr &multiplexId = product.item->property(
StringConstants::multiplexConfigurationIdProperty());
@@ -985,11 +999,34 @@ void ModuleLoader::prepareProduct(ProjectContext *projectContext, Item *productI
productContext.scope->setFile(productItem->file());
productContext.scope->setScope(productContext.project->scope);
- mergeExportItems(productContext);
+ const bool hasExportItems = mergeExportItems(productContext);
setScopeForDescendants(productItem, productContext.scope);
projectContext->products.push_back(productContext);
+
+ if (!hasExportItems || productContext.name.startsWith(shadowProductPrefix()))
+ return;
+
+ // This "shadow product" exists only to pull in a dependency on the actual product
+ // and nothing else, thus providing us with the pure environment that we need to
+ // evaluate the product's exported properties in isolation in the project resolver.
+ Item * const importer = Item::create(productItem->pool(), ItemType::Product);
+ importer->setProperty(QLatin1String("name"),
+ VariantValue::create(shadowProductPrefix() + productContext.name));
+ importer->setFile(productItem->file());
+ importer->setLocation(productItem->location());
+ importer->setScope(projectContext->scope);
+ importer->setupForBuiltinType(m_logger);
+ Item * const dependsItem = Item::create(productItem->pool(), ItemType::Depends);
+ dependsItem->setProperty(QLatin1String("name"), VariantValue::create(productContext.name));
+ dependsItem->setProperty(QLatin1String("required"), VariantValue::create(false));
+ dependsItem->setFile(importer->file());
+ dependsItem->setLocation(importer->location());
+ dependsItem->setupForBuiltinType(m_logger);
+ Item::addChild(importer, dependsItem);
+ Item::addChild(productItem, importer);
+ prepareProduct(projectContext, importer);
}
void ModuleLoader::setupProductDependencies(ProductContext *productContext)
@@ -1632,7 +1669,7 @@ static void adjustParametersScopes(Item *item, Item *scope)
}
}
-void ModuleLoader::mergeExportItems(const ProductContext &productContext)
+bool ModuleLoader::mergeExportItems(const ProductContext &productContext)
{
std::vector<Item *> exportItems;
QList<Item *> children = productContext.item->children();
@@ -1701,6 +1738,7 @@ void ModuleLoader::mergeExportItems(const ProductContext &productContext)
pmi.exportItem = merged;
pmi.multiplexId = productContext.multiplexConfigurationId;
productContext.project->topLevelProject->productModules.insert(productContext.name, pmi);
+ return exportItems.size() > 0;
}
Item *ModuleLoader::loadItemFromFile(const QString &filePath)
diff --git a/src/lib/corelib/language/moduleloader.h b/src/lib/corelib/language/moduleloader.h
index 8cc8a6e81..cdc6390d8 100644
--- a/src/lib/corelib/language/moduleloader.h
+++ b/src/lib/corelib/language/moduleloader.h
@@ -266,7 +266,7 @@ private:
void adjustDefiningItemsInGroupModuleInstances(const Item::Module &module,
const Item::Modules &dependentModules);
- void mergeExportItems(const ProductContext &productContext);
+ bool mergeExportItems(const ProductContext &productContext);
void resolveDependencies(DependsContext *dependsContext, Item *item);
class ItemModuleList;
void resolveDependsItem(DependsContext *dependsContext, Item *parentItem, Item *dependsItem,
diff --git a/src/lib/corelib/language/preparescriptobserver.cpp b/src/lib/corelib/language/preparescriptobserver.cpp
index 21d98ca11..eca0ccf29 100644
--- a/src/lib/corelib/language/preparescriptobserver.cpp
+++ b/src/lib/corelib/language/preparescriptobserver.cpp
@@ -69,6 +69,11 @@ void PrepareScriptObserver::onPropertyRead(const QScriptValue &object, const QSt
engine()->addImportRequestedInScript(object.objectId());
return;
}
+ const auto exportsIt = m_exportsObjectIds.find(value.objectId());
+ if (exportsIt != m_exportsObjectIds.cend()) {
+ engine()->addRequestedExport(exportsIt->second);
+ return;
+ }
const auto it = m_parameterObjects.find(objectId);
if (it != m_parameterObjects.cend()) {
engine()->addPropertyRequestedInScript(
diff --git a/src/lib/corelib/language/preparescriptobserver.h b/src/lib/corelib/language/preparescriptobserver.h
index e7aae4e89..b00c66195 100644
--- a/src/lib/corelib/language/preparescriptobserver.h
+++ b/src/lib/corelib/language/preparescriptobserver.h
@@ -50,6 +50,7 @@
namespace qbs {
namespace Internal {
+class ResolvedProduct;
class ScriptEngine;
class PrepareScriptObserver : public ScriptPropertyObserver
@@ -62,6 +63,11 @@ public:
m_projectObjectIds.insert(std::make_pair(projectId, projectName));
}
+ void addExportsObjectId(qint64 exportsId, const ResolvedProduct *product)
+ {
+ m_exportsObjectIds.insert(std::make_pair(exportsId, product));
+ }
+
bool addImportId(qint64 importId) { return m_importIds.insert(importId).second; }
void clearImportIds() { m_importIds.clear(); }
void addParameterObjectId(qint64 id, const QString &productName, const QString &depName,
@@ -77,6 +83,7 @@ private:
std::unordered_map<qint64, QString> m_projectObjectIds;
std::unordered_map<qint64, std::pair<QString, QString>> m_parameterObjects;
+ std::unordered_map<qint64, const ResolvedProduct *> m_exportsObjectIds;
Set<qint64> m_importIds;
};
diff --git a/src/lib/corelib/language/projectresolver.cpp b/src/lib/corelib/language/projectresolver.cpp
index df2c5fcb3..7028e28ad 100644
--- a/src/lib/corelib/language/projectresolver.cpp
+++ b/src/lib/corelib/language/projectresolver.cpp
@@ -40,6 +40,7 @@
#include "projectresolver.h"
#include "artifactproperties.h"
+#include "builtindeclarations.h"
#include "evaluator.h"
#include "filecontext.h"
#include "item.h"
@@ -49,20 +50,24 @@
#include "scriptengine.h"
#include "value.h"
+#include <jsextensions/jsextensions.h>
#include <jsextensions/moduleproperties.h>
#include <logging/categories.h>
#include <logging/translator.h>
#include <tools/error.h>
#include <tools/fileinfo.h>
+#include <tools/jsliterals.h>
#include <tools/profiling.h>
#include <tools/progressobserver.h>
#include <tools/scripttools.h>
#include <tools/qbsassert.h>
#include <tools/qttools.h>
#include <tools/setupprojectparameters.h>
+#include <tools/stlutils.h>
#include <tools/stringconstants.h>
#include <QtCore/qdir.h>
+#include <QtCore/qregularexpression.h>
#include <algorithm>
#include <queue>
@@ -255,6 +260,7 @@ TopLevelProjectPtr ProjectResolver::resolveTopLevelProject()
project->buildSystemFiles.unite(m_engine->imports());
makeSubProjectNamesUniqe(project);
resolveProductDependencies(projectContext);
+ collectExportedProductDependencies();
checkForDuplicateProductNames(project);
for (const ResolvedProductPtr &product : project->allProducts()) {
@@ -489,7 +495,8 @@ void ProjectResolver::resolveProductFully(Item *item, ProjectContext *projectCon
{ ItemType::Rule, &ProjectResolver::resolveRule },
{ ItemType::FileTagger, &ProjectResolver::resolveFileTagger },
{ ItemType::Group, &ProjectResolver::resolveGroup },
- { ItemType::Export, &ProjectResolver::ignoreItem },
+ { ItemType::Product, &ProjectResolver::resolveShadowProduct },
+ { ItemType::Export, &ProjectResolver::resolveExport },
{ ItemType::Probe, &ProjectResolver::ignoreItem },
{ ItemType::PropertyOptions, &ProjectResolver::ignoreItem }
};
@@ -654,7 +661,7 @@ QVariantMap ProjectResolver::resolveAdditionalModuleProperties(const Item *group
for (const QString &prop : qAsConst(propsForModule))
reusableValues.remove(prop);
modulesMap.insert(fullModName,
- evaluateProperties(module.item, module.item, reusableValues, true));
+ evaluateProperties(module.item, module.item, reusableValues, true, true));
}
m_evaluator->clearPathPropertiesBaseDir();
return modulesMap;
@@ -815,6 +822,254 @@ void ProjectResolver::resolveGroupFully(Item *item, ProjectResolver::ProjectCont
resolveGroup(childItem, projectContext);
}
+void ProjectResolver::adaptExportedPropertyValues()
+{
+ ExportedModule &m = m_productContext->product->exportedModule;
+ const QVariantList prefixList = m.propertyValues.take(
+ StringConstants::prefixMappingProperty()).toList();
+ if (prefixList.empty())
+ return;
+ QVariantMap prefixMap;
+ for (const QVariant &v : prefixList) {
+ const QVariantMap o = v.toMap();
+ prefixMap.insert(o.value(QLatin1String("prefix")).toString(),
+ o.value(QLatin1String("replacement")).toString());
+ }
+ static const auto stringMapper = [](const QVariantMap &mappings, const QString &value)
+ -> QString {
+ for (auto it = mappings.cbegin(); it != mappings.cend(); ++it) {
+ if (value.startsWith(it.key()))
+ return it.value().toString() + value.mid(it.key().size());
+ }
+ return value;
+ };
+ static const auto stringListMapper = [](const QVariantMap &mappings, const QStringList &value)
+ -> QStringList {
+ QStringList result;
+ result.reserve(value.size());
+ for (const QString &s : value) {
+ result.push_back(stringMapper(mappings, s));
+ }
+ return result;
+ };
+ static const std::function<QVariant(const QVariantMap &, const QVariant &)> mapper
+ = [](const QVariantMap &mappings, const QVariant &value) -> QVariant {
+ switch (static_cast<QMetaType::Type>(value.type())) {
+ case QMetaType::QString:
+ return stringMapper(mappings, value.toString());
+ case QMetaType::QStringList:
+ return stringListMapper(mappings, value.toStringList());
+ case QMetaType::QVariantMap: {
+ QVariantMap m = value.toMap();
+ for (auto it = m.begin(); it != m.end(); ++it)
+ it.value() = mapper(mappings, it.value());
+ return m;
+ }
+ default:
+ return value;
+ }
+ };
+ for (auto it = m.propertyValues.begin(); it != m.propertyValues.end(); ++it)
+ it.value() = mapper(prefixMap, it.value());
+ for (auto it = m.modulePropertyValues.begin(); it != m.modulePropertyValues.end(); ++it)
+ it.value() = mapper(prefixMap, it.value());
+ for (ExportedModuleDependency &dep : m.moduleDependencies) {
+ for (auto it = dep.moduleProperties.begin(); it != dep.moduleProperties.end(); ++it)
+ it.value() = mapper(prefixMap, it.value());
+ }
+}
+
+void ProjectResolver::collectExportedProductDependencies()
+{
+ ResolvedProductPtr dummyProduct = ResolvedProduct::create();
+ dummyProduct->enabled = false;
+ for (const auto &exportingProductInfo : qAsConst(m_productExportInfo)) {
+ const ResolvedProductPtr exportingProduct = exportingProductInfo.first;
+ if (!exportingProduct->enabled)
+ continue;
+ Item * const importingProductItem = exportingProductInfo.second;
+ std::vector<QString> directDepNames;
+ for (const Item::Module &m : importingProductItem->modules()) {
+ if (m.name.toString() == exportingProduct->name) {
+ for (const Item::Module &dep : m.item->modules()) {
+ if (dep.isProduct)
+ directDepNames.push_back(dep.name.toString());
+ }
+ break;
+ }
+ }
+ const ModuleLoaderResult::ProductInfo &importingProductInfo
+ = m_loadResult.productInfos.value(importingProductItem);
+ const ProductDependencyInfos &depInfos
+ = getProductDependencies(dummyProduct, importingProductInfo);
+ for (const auto &dep : depInfos.dependencies) {
+ if (dep.product == exportingProduct)
+ continue;
+
+ // Filter out indirect dependencies.
+ // TODO: Depends items using "profile" or "productTypes" will not work.
+ if (!contains(directDepNames, dep.product->name))
+ continue;
+
+ exportingProduct->exportedModule.productDependencies.insert(dep.product);
+ if (!dep.parameters.isEmpty()) {
+ exportingProduct->exportedModule.dependencyParameters.insert(dep.product,
+ dep.parameters);
+ }
+ }
+ }
+}
+
+void ProjectResolver::resolveShadowProduct(Item *item, ProjectResolver::ProjectContext *)
+{
+ for (const auto &m : item->modules()) {
+ if (m.name.toString() != m_productContext->product->name)
+ continue;
+ collectPropertiesForExportItem(m.item);
+ for (const auto &dep : m.item->modules())
+ collectPropertiesForModuleInExportItem(dep);
+ break;
+ }
+ adaptExportedPropertyValues();
+ m_productExportInfo.push_back(std::make_pair(m_productContext->product, item));
+}
+
+void ProjectResolver::setupExportedProperties(const Item *item, const QString &namePrefix,
+ std::vector<ExportedProperty> &properties)
+{
+ const auto &props = item->properties();
+ for (auto it = props.cbegin(); it != props.cend(); ++it) {
+ const QString qualifiedName = namePrefix.isEmpty()
+ ? it.key() : namePrefix + QLatin1Char('.') + it.key();
+ if (item->type() == ItemType::Export
+ && qualifiedName == StringConstants::prefixMappingProperty()) {
+ continue;
+ }
+ const ValuePtr &v = it.value();
+ if (v->type() == Value::ItemValueType) {
+ setupExportedProperties(std::static_pointer_cast<ItemValue>(v)->item(),
+ qualifiedName, properties);
+ continue;
+ }
+ ExportedProperty exportedProperty;
+ exportedProperty.fullName = qualifiedName;
+ exportedProperty.type = item->propertyDeclaration(it.key()).type();
+ if (v->type() == Value::VariantValueType) {
+ exportedProperty.sourceCode = toJSLiteral(
+ std::static_pointer_cast<VariantValue>(v)->value());
+ } else {
+ QBS_CHECK(v->type() == Value::JSSourceValueType);
+ const JSSourceValue * const sv = static_cast<JSSourceValue *>(v.get());
+ exportedProperty.sourceCode = sv->sourceCode().toString();
+ }
+ const ItemDeclaration itemDecl
+ = BuiltinDeclarations::instance().declarationsForType(item->type());
+ PropertyDeclaration propertyDecl;
+ for (const PropertyDeclaration &decl : itemDecl.properties()) {
+ if (decl.name() == it.key()) {
+ propertyDecl = decl;
+ exportedProperty.isBuiltin = true;
+ break;
+ }
+ }
+
+ // Do not add built-in properties that were left at their default value.
+ if (!exportedProperty.isBuiltin || m_evaluator->isNonDefaultValue(item, it.key()))
+ properties.push_back(exportedProperty);
+ }
+
+ // Order the list of properties, so the output won't look so random.
+ static const auto less = [](const ExportedProperty &p1, const ExportedProperty &p2) -> bool {
+ const int p1ComponentCount = p1.fullName.count(QLatin1Char('.'));
+ const int p2ComponentCount = p2.fullName.count(QLatin1Char('.'));
+ if (p1.isBuiltin && !p2.isBuiltin)
+ return true;
+ if (!p1.isBuiltin && p2.isBuiltin)
+ return false;
+ if (p1ComponentCount < p2ComponentCount)
+ return true;
+ if (p1ComponentCount > p2ComponentCount)
+ return false;
+ return p1.fullName < p2.fullName;
+ };
+ std::sort(properties.begin(), properties.end(), less);
+}
+
+static bool usesImport(const ExportedProperty &prop, const QRegularExpression &regex)
+{
+ return regex.match(prop.sourceCode).hasMatch();
+}
+
+static bool usesImport(const ExportedItem &item, const QRegularExpression &regex)
+{
+ return any_of(item.properties,
+ [regex](const ExportedProperty &p) { return usesImport(p, regex); })
+ || any_of(item.children,
+ [regex](const ExportedItemPtr &child) { return usesImport(*child, regex); });
+}
+
+static bool usesImport(const ExportedModule &module, const QString &name)
+{
+ // Imports are used in two ways:
+ // (1) var f = new TextFile(...);
+ // (2) var path = FileInfo.joinPaths(...)
+ const QString pattern
+ = QStringLiteral("(?:new[[:space:]]+%1[[:space:]]+\\()|(?:[^[:alnum:]_]?%1\\.)");
+ const QRegularExpression regex(pattern.arg(name)); // std::regex is much slower
+ return any_of(module.m_properties,
+ [regex](const ExportedProperty &p) { return usesImport(p, regex); })
+ || any_of(module.children,
+ [regex](const ExportedItemPtr &child) { return usesImport(*child, regex); });
+}
+
+static QString getLineAtLocation(const CodeLocation &loc, const QString &content)
+{
+ int pos = 0;
+ int currentLine = 1;
+ while (currentLine < loc.line()) {
+ while (content.at(pos++) != QLatin1Char('\n'))
+ ;
+ ++currentLine;
+ }
+ const int eolPos = content.indexOf(QLatin1Char('\n'), pos);
+ return content.mid(pos, eolPos - pos);
+}
+
+void ProjectResolver::resolveExport(Item *exportItem, ProjectContext *)
+{
+ ExportedModule &exportedModule = m_productContext->product->exportedModule;
+ setupExportedProperties(exportItem, QString(), exportedModule.m_properties);
+ for (const Item * const child : exportItem->children())
+ exportedModule.children.push_back(resolveExportChild(child, exportedModule));
+ for (const JsImport &jsImport : exportItem->file()->jsImports()) {
+ if (usesImport(exportedModule, jsImport.scopeName)) {
+ exportedModule.importStatements << getLineAtLocation(jsImport.location,
+ exportItem->file()->content());
+ }
+ }
+ for (const QString &builtinImport: JsExtensions::extensionNames()) {
+ if (usesImport(exportedModule, builtinImport))
+ exportedModule.importStatements << QStringLiteral("import qbs.") + builtinImport;
+ }
+}
+
+// TODO: This probably wouldn't be necessary if we had item serialization.
+std::unique_ptr<ExportedItem> ProjectResolver::resolveExportChild(const Item *item,
+ const ExportedModule &module)
+{
+ std::unique_ptr<ExportedItem> exportedItem(new ExportedItem);
+
+ // This is the type of the built-in base item. It may turn out that we need to support
+ // derived items under Export. In that case, we probably need a new Item member holding
+ // the original type name.
+ exportedItem->name = item->typeName();
+
+ for (const Item * const child : item->children())
+ exportedItem->children.push_back(resolveExportChild(child, module));
+ setupExportedProperties(item, QString(), exportedItem->properties);
+ return exportedItem;
+}
+
QString ProjectResolver::sourceCodeAsFunction(const JSSourceValueConstPtr &value,
const PropertyDeclaration &decl) const
@@ -1141,6 +1396,76 @@ void ProjectResolver::printProfilingInfo()
.arg(elapsedTimeString(m_elapsedTimeGroups));
}
+class TempScopeSetter
+{
+public:
+ TempScopeSetter(Item * item, Item *newScope) : m_item(item), m_oldScope(item->scope())
+ {
+ item->setScope(newScope);
+ }
+ ~TempScopeSetter() { m_item->setScope(m_oldScope); }
+private:
+ Item * const m_item;
+ Item * const m_oldScope;
+};
+
+void ProjectResolver::collectPropertiesForExportItem(Item *productModuleInstance)
+{
+ Item * const exportItem = productModuleInstance->prototype();
+ QBS_CHECK(exportItem && exportItem->type() == ItemType::Export);
+ TempScopeSetter tempScopeSetter(exportItem, productModuleInstance->scope());
+ const ItemDeclaration::Properties exportDecls = BuiltinDeclarations::instance()
+ .declarationsForType(ItemType::Export).properties();
+ ExportedModule &exportedModule = m_productContext->product->exportedModule;
+ const auto &props = exportItem->properties();
+ for (auto it = props.begin(); it != props.end(); ++it) {
+ const auto match
+ = [it](const PropertyDeclaration &decl) { return decl.name() == it.key(); };
+ if (it.key() != StringConstants::prefixMappingProperty() &&
+ std::find_if(exportDecls.begin(), exportDecls.end(), match) != exportDecls.end()) {
+ continue;
+ }
+ if (it.value()->type() == Value::ItemValueType) {
+ collectPropertiesForExportItem(it.key(), it.value(), productModuleInstance,
+ exportedModule.modulePropertyValues);
+ } else {
+ evaluateProperty(exportItem, it.key(), it.value(), exportedModule.propertyValues,
+ false);
+ }
+ }
+}
+
+// Collects module properties assigned to in other (higher-level) modules.
+void ProjectResolver::collectPropertiesForModuleInExportItem(const Item::Module &module)
+{
+ ExportedModule &exportedModule = m_productContext->product->exportedModule;
+ if (module.isProduct || module.name.first() == StringConstants::qbsModule())
+ return;
+ const auto checkName = [module](const ExportedModuleDependency &d) {
+ return module.name.toString() == d.name;
+ };
+ if (any_of(exportedModule.moduleDependencies, checkName))
+ return;
+
+ Item *modulePrototype = module.item->prototype();
+ while (modulePrototype && modulePrototype->type() != ItemType::Module)
+ modulePrototype = modulePrototype->prototype();
+ if (!modulePrototype) // Can happen for broken products in relaxed mode.
+ return;
+ TempScopeSetter tempScopeSetter(modulePrototype, module.item->scope());
+ const Item::PropertyMap &props = modulePrototype->properties();
+ ExportedModuleDependency dep;
+ dep.name = module.name.toString();
+ for (auto it = props.begin(); it != props.end(); ++it) {
+ if (it.value()->type() == Value::ItemValueType)
+ collectPropertiesForExportItem(it.key(), it.value(), module.item, dep.moduleProperties);
+ }
+ exportedModule.moduleDependencies.push_back(dep);
+
+ for (const auto &dep : module.item->modules())
+ collectPropertiesForModuleInExportItem(dep);
+}
+
static bool hasDependencyCycle(Set<ResolvedProduct *> *checked,
Set<ResolvedProduct *> *branch,
const ResolvedProductPtr &product,
@@ -1283,82 +1608,127 @@ QVariantMap ProjectResolver::evaluateModuleValues(Item *item, bool lookupPrototy
QVariantMap moduleValues;
for (const Item::Module &module : item->modules()) {
const QString fullName = module.name.toString();
- moduleValues[fullName] = evaluateProperties(module.item, lookupPrototype);
+ moduleValues[fullName] = evaluateProperties(module.item, lookupPrototype, true);
}
return moduleValues;
}
-QVariantMap ProjectResolver::evaluateProperties(Item *item, bool lookupPrototype)
+QVariantMap ProjectResolver::evaluateProperties(Item *item, bool lookupPrototype, bool checkErrors)
{
const QVariantMap tmplt;
- return evaluateProperties(item, item, tmplt, lookupPrototype);
+ return evaluateProperties(item, item, tmplt, lookupPrototype, checkErrors);
}
QVariantMap ProjectResolver::evaluateProperties(const Item *item, const Item *propertiesContainer,
- const QVariantMap &tmplt, bool lookupPrototype)
+ const QVariantMap &tmplt, bool lookupPrototype, bool checkErrors)
{
AccumulatingTimer propEvalTimer(m_setupParams.logElapsedTime()
? &m_elapsedTimeAllPropEval : nullptr);
QVariantMap result = tmplt;
for (QMap<QString, ValuePtr>::const_iterator it = propertiesContainer->properties().begin();
- it != propertiesContainer->properties().end(); ++it)
- {
+ it != propertiesContainer->properties().end(); ++it) {
checkCancelation();
- switch (it.value()->type()) {
- case Value::ItemValueType:
- {
- // Ignore items. Those point to module instances
- // and are handled in evaluateModuleValues().
+ evaluateProperty(item, it.key(), it.value(), result, checkErrors);
+ }
+ return lookupPrototype && propertiesContainer->prototype()
+ ? evaluateProperties(item, propertiesContainer->prototype(), result, true, checkErrors)
+ : result;
+}
+
+void ProjectResolver::evaluateProperty(const Item *item, const QString &propName,
+ const ValuePtr &propValue, QVariantMap &result, bool checkErrors)
+{
+ switch (propValue->type()) {
+ case Value::ItemValueType:
+ {
+ // Ignore items. Those point to module instances
+ // and are handled in evaluateModuleValues().
+ break;
+ }
+ case Value::JSSourceValueType:
+ {
+ if (result.contains(propName))
+ break;
+ const PropertyDeclaration pd = item->propertyDeclaration(propName);
+ if (pd.flags().testFlag(PropertyDeclaration::PropertyNotAvailableInConfig)) {
break;
}
- case Value::JSSourceValueType:
- {
- if (result.contains(it.key()))
- break;
- const PropertyDeclaration pd = item->propertyDeclaration(it.key());
- if (pd.flags().testFlag(PropertyDeclaration::PropertyNotAvailableInConfig)) {
- break;
- }
-
- const QScriptValue scriptValue = m_evaluator->property(item, it.key());
- if (Q_UNLIKELY(m_evaluator->engine()->hasErrorOrException(scriptValue))) {
- throw ErrorInfo(m_evaluator->engine()->lastError(scriptValue,
- it.value()->location()));
- }
+ const QScriptValue scriptValue = m_evaluator->property(item, propName);
+ if (checkErrors && Q_UNLIKELY(m_evaluator->engine()->hasErrorOrException(scriptValue))) {
+ throw ErrorInfo(m_evaluator->engine()->lastError(scriptValue,
+ propValue->location()));
+ }
- // NOTE: Loses type information if scriptValue.isUndefined == true,
- // as such QScriptValues become invalid QVariants.
- QVariant v = scriptValue.toVariant();
- if (pd.type() == PropertyDeclaration::Path && v.isValid()) {
- v = v.toString();
- } else if (pd.type() == PropertyDeclaration::PathList
- || pd.type() == PropertyDeclaration::StringList) {
- v = v.toStringList();
- } else if (pd.type() == PropertyDeclaration::VariantList) {
- v = v.toList();
- }
- result[it.key()] = v;
- break;
+ // NOTE: Loses type information if scriptValue.isUndefined == true,
+ // as such QScriptValues become invalid QVariants.
+ QVariant v = scriptValue.isFunction() ? scriptValue.toString() : scriptValue.toVariant();
+ if (pd.type() == PropertyDeclaration::Path && v.isValid()) {
+ v = v.toString();
+ } else if (pd.type() == PropertyDeclaration::PathList
+ || pd.type() == PropertyDeclaration::StringList) {
+ v = v.toStringList();
+ } else if (pd.type() == PropertyDeclaration::VariantList) {
+ v = v.toList();
}
- case Value::VariantValueType:
- {
- if (result.contains(it.key()))
- break;
- VariantValuePtr vvp = std::static_pointer_cast<VariantValue>(it.value());
- QVariant v = vvp->value();
+ result[propName] = v;
+ break;
+ }
+ case Value::VariantValueType:
+ {
+ if (result.contains(propName))
+ break;
+ VariantValuePtr vvp = std::static_pointer_cast<VariantValue>(propValue);
+ QVariant v = vvp->value();
- if (v.isNull() && !item->propertyDeclaration(it.key()).isScalar()) // QTBUG-51237
- v = QStringList();
+ if (v.isNull() && !item->propertyDeclaration(propName).isScalar()) // QTBUG-51237
+ v = QStringList();
- result[it.key()] = v;
- break;
- }
- }
+ result[propName] = v;
+ break;
+ }
+ }
+}
+
+void ProjectResolver::collectPropertiesForExportItem(const QualifiedId &moduleName,
+ const ValuePtr &value, Item *moduleInstance, QVariantMap &moduleProps)
+{
+ QBS_CHECK(value->type() == Value::ItemValueType);
+ Item * const itemValueItem = std::static_pointer_cast<ItemValue>(value)->item();
+ if (itemValueItem->type() == ItemType::ModuleInstance) {
+ struct EvalPreparer {
+ EvalPreparer(Item *valueItem, Item *moduleInstance, const QualifiedId &moduleName)
+ : valueItem(valueItem), oldScope(valueItem->scope()),
+ hadName(!!valueItem->variantProperty(StringConstants::nameProperty()))
+ {
+ valueItem->setScope(moduleInstance);
+ if (!hadName) {
+ // EvaluatorScriptClass expects a name here.
+ valueItem->setProperty(StringConstants::nameProperty(),
+ VariantValue::create(moduleName.toString()));
+ }
+ }
+ ~EvalPreparer()
+ {
+ valueItem->setScope(oldScope);
+ if (!hadName)
+ valueItem->setProperty(StringConstants::nameProperty(), VariantValuePtr());
+ }
+ Item * const valueItem;
+ Item * const oldScope;
+ const bool hadName;
+ };
+ EvalPreparer ep(itemValueItem, moduleInstance, moduleName);
+ moduleProps.insert(moduleName.toString(), evaluateProperties(itemValueItem, false, false));
+ return;
+ }
+ QBS_CHECK(itemValueItem->type() == ItemType::ModulePrefix);
+ const Item::PropertyMap &props = itemValueItem->properties();
+ for (auto it = props.begin(); it != props.end(); ++it) {
+ QualifiedId fullModuleName = moduleName;
+ fullModuleName << it.key();
+ collectPropertiesForExportItem(fullModuleName, it.value(), moduleInstance, moduleProps);
}
- return lookupPrototype && propertiesContainer->prototype()
- ? evaluateProperties(item, propertiesContainer->prototype(), result, true)
- : result;
}
void ProjectResolver::createProductConfig(ResolvedProduct *product)
@@ -1367,7 +1737,7 @@ void ProjectResolver::createProductConfig(ResolvedProduct *product)
m_evaluator->setPathPropertiesBaseDir(m_productContext->product->sourceDirectory);
product->moduleProperties->setValue(evaluateModuleValues(m_productContext->item));
product->productProperties = evaluateProperties(m_productContext->item, m_productContext->item,
- QVariantMap());
+ QVariantMap(), true, true);
m_evaluator->clearPathPropertiesBaseDir();
}
diff --git a/src/lib/corelib/language/projectresolver.h b/src/lib/corelib/language/projectresolver.h
index 764eea1a7..f0f67c142 100644
--- a/src/lib/corelib/language/projectresolver.h
+++ b/src/lib/corelib/language/projectresolver.h
@@ -53,6 +53,7 @@
#include <QtCore/qstringlist.h>
#include <utility>
+#include <vector>
namespace qbs {
namespace Internal {
@@ -106,6 +107,10 @@ private:
const QVariantMap &currentValues);
void resolveGroup(Item *item, ProjectContext *projectContext);
void resolveGroupFully(Item *item, ProjectContext *projectContext, bool isEnabled);
+ void resolveShadowProduct(Item *item, ProjectContext *);
+ void resolveExport(Item *exportItem, ProjectContext *);
+ std::unique_ptr<ExportedItem> resolveExportChild(const Item *item,
+ const ExportedModule &module);
void resolveRule(Item *item, ProjectContext *projectContext);
void resolveRuleArtifact(const RulePtr &rule, Item *item);
void resolveRuleArtifactBinding(const RuleArtifactPtr &ruleArtifact, Item *item,
@@ -117,11 +122,16 @@ private:
void postProcess(const ResolvedProductPtr &product, ProjectContext *projectContext) const;
void applyFileTaggers(const ResolvedProductPtr &product) const;
QVariantMap evaluateModuleValues(Item *item, bool lookupPrototype = true);
- QVariantMap evaluateProperties(Item *item, bool lookupPrototype = true);
+ QVariantMap evaluateProperties(Item *item, bool lookupPrototype, bool checkErrors);
QVariantMap evaluateProperties(const Item *item, const Item *propertiesContainer,
- const QVariantMap &tmplt, bool lookupPrototype = true);
+ const QVariantMap &tmplt, bool lookupPrototype,
+ bool checkErrors);
+ void evaluateProperty(const Item *item, const QString &propName, const ValuePtr &propValue,
+ QVariantMap &result, bool checkErrors);
void createProductConfig(ResolvedProduct *product);
ProjectContext createProjectContext(ProjectContext *parentProjectContext) const;
+ void adaptExportedPropertyValues();
+ void collectExportedProductDependencies();
struct ProductDependencyInfo
{
@@ -150,6 +160,14 @@ private:
const QList<SourceArtifactPtr> &artifacts);
void printProfilingInfo();
+ void collectPropertiesForExportItem(Item *productModuleInstance);
+ void collectPropertiesForModuleInExportItem(const Item::Module &module);
+
+ void collectPropertiesForExportItem(const QualifiedId &moduleName,
+ const ValuePtr &value, Item *moduleInstance, QVariantMap &moduleProps);
+ void setupExportedProperties(const Item *item, const QString &namePrefix,
+ std::vector<ExportedProperty> &properties);
+
Evaluator *m_evaluator;
Logger &m_logger;
ScriptEngine *m_engine;
@@ -166,6 +184,7 @@ private:
const SetupProjectParameters &m_setupParams;
ModuleLoaderResult m_loadResult;
Set<CodeLocation> m_groupLocationWarnings;
+ std::vector<std::pair<ResolvedProductPtr, Item *>> m_productExportInfo;
qint64 m_elapsedTimeModPropEval;
qint64 m_elapsedTimeAllPropEval;
qint64 m_elapsedTimeGroups;
diff --git a/src/lib/corelib/language/propertydeclaration.cpp b/src/lib/corelib/language/propertydeclaration.cpp
index 070623bab..c7826dc39 100644
--- a/src/lib/corelib/language/propertydeclaration.cpp
+++ b/src/lib/corelib/language/propertydeclaration.cpp
@@ -142,7 +142,12 @@ PropertyDeclaration::Type PropertyDeclaration::propertyTypeFromString(const QStr
QString PropertyDeclaration::typeString() const
{
- switch (type()) {
+ return typeString(type());
+}
+
+QString PropertyDeclaration::typeString(PropertyDeclaration::Type t)
+{
+ switch (t) {
case Boolean: return boolString();
case Integer: return intString();
case Path: return StringConstants::pathType();
diff --git a/src/lib/corelib/language/propertydeclaration.h b/src/lib/corelib/language/propertydeclaration.h
index 5a65a3373..874275bde 100644
--- a/src/lib/corelib/language/propertydeclaration.h
+++ b/src/lib/corelib/language/propertydeclaration.h
@@ -89,6 +89,7 @@ public:
static Type propertyTypeFromString(const QString &typeName);
QString typeString() const;
+ static QString typeString(Type t);
const QString &name() const;
void setName(const QString &name);
diff --git a/src/lib/corelib/language/scriptengine.h b/src/lib/corelib/language/scriptengine.h
index 4157ea762..11ed51a49 100644
--- a/src/lib/corelib/language/scriptengine.h
+++ b/src/lib/corelib/language/scriptengine.h
@@ -129,12 +129,14 @@ public:
m_requestedArtifacts.setArtifactsForTag(product, tag);
}
void addPropertyRequestedFromArtifact(const Artifact *artifact, const Property &property);
+ void addRequestedExport(const ResolvedProduct *product) { m_requestedExports.insert(product); }
void clearRequestedProperties() {
m_propertiesRequestedInScript.clear();
m_propertiesRequestedFromArtifact.clear();
m_importsRequestedInScript.clear();
m_productsWithRequestedDependencies.clear();
m_requestedArtifacts.clear();
+ m_requestedExports.clear();
}
PropertySet propertiesRequestedInScript() const { return m_propertiesRequestedInScript; }
QHash<QString, PropertySet> propertiesRequestedFromArtifact() const {
@@ -149,6 +151,7 @@ public:
return RequestedDependencies(m_productsWithRequestedDependencies);
}
RequestedArtifacts requestedArtifacts() const { return m_requestedArtifacts; }
+ Set<const ResolvedProduct *> requestedExports() const { return m_requestedExports; }
void addImportRequestedInScript(qint64 importValueId);
std::vector<QString> importedFilesUsedInScript() const;
@@ -327,8 +330,8 @@ private:
std::vector<qint64> m_importsRequestedInScript;
Set<const ResolvedProduct *> m_productsWithRequestedDependencies;
RequestedArtifacts m_requestedArtifacts;
+ Set<const ResolvedProduct *> m_requestedExports;
ObserveMode m_observeMode = ObserveMode::Disabled;
-
std::unordered_map<const ResolvedProduct *, QScriptValue> m_productScriptValues;
std::unordered_map<const ResolvedProject *, QScriptValue> m_projectScriptValues;
std::unordered_map<const ResolvedModule *, QScriptValue> m_moduleScriptValues;