aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/corelib/language/item.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/corelib/language/item.h')
-rw-r--r--src/lib/corelib/language/item.h125
1 files changed, 99 insertions, 26 deletions
diff --git a/src/lib/corelib/language/item.h b/src/lib/corelib/language/item.h
index 22cf6b810..d0dde98c4 100644
--- a/src/lib/corelib/language/item.h
+++ b/src/lib/corelib/language/item.h
@@ -46,12 +46,16 @@
#include "qualifiedid.h"
#include <parser/qmljsmemorypool_p.h>
#include <tools/codelocation.h>
+#include <tools/deprecationwarningmode.h>
#include <tools/error.h>
#include <tools/version.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
+#include <atomic>
+#include <mutex>
+#include <utility>
#include <vector>
namespace qbs {
@@ -62,55 +66,87 @@ namespace Internal {
class ItemObserver;
class ItemPool;
class Logger;
+class ModuleItemLocker;
+class ProductContext;
class QBS_AUTOTEST_EXPORT Item : public QbsQmlJS::Managed
{
friend class ASTPropertiesItemHandler;
friend class ItemPool;
friend class ItemReaderASTVisitor;
+ friend class ModuleItemLocker;
Q_DISABLE_COPY(Item)
- Item(ItemPool *pool, ItemType type);
+ Item(ItemType type) : m_type(type) {}
public:
struct Module
{
- Module()
- : item(nullptr), isProduct(false), required(true)
- {}
-
QualifiedId name;
- Item *item;
- bool isProduct;
- bool requiredValue = true; // base value of the required prop
- bool required;
- bool fallbackEnabled = true;
+ Item *item = nullptr;
+ ProductContext *product = nullptr; // Set if and only if the dep is a product.
+
+ // All the sites that declared an explicit dependency on this module. Can contain any
+ // number of module instances and at most one product.
+ using ParametersWithPriority = std::pair<QVariantMap, int>;
+ struct LoadContext {
+ LoadContext(Item *dependsItem,
+ const ParametersWithPriority &parameters)
+ : dependsItem(dependsItem), parameters(parameters) {}
+ LoadContext(Item *dependsItem, ParametersWithPriority &&parameters)
+ : dependsItem(dependsItem), parameters(std::move(parameters)) {}
+
+ LoadContext(const LoadContext &) = default;
+ LoadContext(LoadContext &&) = default;
+ LoadContext &operator=(const LoadContext &) = default;
+ LoadContext &operator=(LoadContext &&) = default;
+
+ Item *loadingItem() const { return dependsItem ? dependsItem->parent() : nullptr; }
+ Item *dependsItem;
+ ParametersWithPriority parameters;
+ };
+ std::vector<LoadContext> loadContexts;
+
QVariantMap parameters;
VersionRange versionRange;
+
+ // The shorter this value, the "closer to the product" we consider the module,
+ // and the higher its precedence is when merging property values.
+ int maxDependsChainLength = 0;
+
+ bool required = true;
};
using Modules = std::vector<Module>;
using PropertyDeclarationMap = QMap<QString, PropertyDeclaration>;
using PropertyMap = QMap<QString, ValuePtr>;
static Item *create(ItemPool *pool, ItemType type);
- Item *clone() const;
- ItemPool *pool() const { return m_pool; }
+ Item *clone(ItemPool &pool) const;
const QString &id() const { return m_id; }
const CodeLocation &location() const { return m_location; }
+ CodeRange codeRange() const;
Item *prototype() const { return m_prototype; }
+ Item *rootPrototype();
Item *scope() const { return m_scope; }
Item *outerItem() const { return m_outerItem; }
Item *parent() const { return m_parent; }
const FileContextPtr &file() const { return m_file; }
const QList<Item *> &children() const { return m_children; }
+ QList<Item *> &children() { return m_children; }
Item *child(ItemType type, bool checkForMultiple = true) const;
- const PropertyMap &properties() const { return m_properties; }
+ const PropertyMap &properties() const { assertModuleLocked(); return m_properties; }
+ PropertyMap &properties() { assertModuleLocked(); return m_properties; }
const PropertyDeclarationMap &propertyDeclarations() const { return m_propertyDeclarations; }
PropertyDeclaration propertyDeclaration(const QString &name, bool allowExpired = true) const;
+
+ // The list of modules is ordered such that dependencies appear before the modules
+ // depending on them.
const Modules &modules() const { return m_modules; }
+ Modules &modules() { return m_modules; }
+
void addModule(const Module &module);
void removeModules() { m_modules.clear(); }
- void setModules(const Modules &modules) { m_modules = modules; }
+ void setModules(const Modules &modules);
ItemType type() const { return m_type; }
void setType(ItemType type) { m_type = type; }
@@ -120,18 +156,20 @@ public:
bool hasOwnProperty(const QString &name) const;
ValuePtr property(const QString &name) const;
ValuePtr ownProperty(const QString &name) const;
- ItemValuePtr itemProperty(const QString &name, const Item *itemTemplate = nullptr);
- ItemValuePtr itemProperty(const QString &name, const ItemValueConstPtr &value);
+ ItemValuePtr itemProperty(const QString &name, ItemPool &pool, const Item *itemTemplate = nullptr);
+ ItemValuePtr itemProperty(const QString &name, const ItemValueConstPtr &value, ItemPool &pool);
JSSourceValuePtr sourceProperty(const QString &name) const;
VariantValuePtr variantProperty(const QString &name) const;
bool isOfTypeOrhasParentOfType(ItemType type) const;
- void setObserver(ItemObserver *observer) const;
+ void addObserver(ItemObserver *observer) const;
+ void removeObserver(ItemObserver *observer) const;
void setProperty(const QString &name, const ValuePtr &value);
- void setProperties(const PropertyMap &props) { m_properties = props; }
+ void setProperties(const PropertyMap &props) { assertModuleLocked(); m_properties = props; }
void removeProperty(const QString &name);
void setPropertyDeclaration(const QString &name, const PropertyDeclaration &declaration);
void setPropertyDeclarations(const PropertyDeclarationMap &decls);
void setLocation(const CodeLocation &location) { m_location = location; }
+ void setEndPosition(const CodePosition &position) { m_endPosition = position; }
void setPrototype(Item *prototype) { m_prototype = prototype; }
void setFile(const FileContextPtr &file) { m_file = file; }
void setId(const QString &id) { m_id = id; }
@@ -144,28 +182,39 @@ public:
static void removeChild(Item *parent, Item *child);
void dump() const;
bool isPresentModule() const;
- void setupForBuiltinType(Logger &logger);
+ bool isFallbackModule() const;
+ void setupForBuiltinType(DeprecationWarningMode deprecationMode, Logger &logger);
void copyProperty(const QString &propertyName, Item *target) const;
void overrideProperties(
const QVariantMap &config,
+ const QString &key,
+ const SetupProjectParameters &parameters,
+ Logger &logger);
+ void overrideProperties(
+ const QVariantMap &config,
const QualifiedId &namePrefix,
const SetupProjectParameters &parameters,
Logger &logger);
private:
ItemValuePtr itemProperty(const QString &name, const Item *itemTemplate,
- const ItemValueConstPtr &itemValue);
+ const ItemValueConstPtr &itemValue, ItemPool &pool);
void dump(int indentation) const;
- ItemPool *m_pool;
- mutable ItemObserver *m_observer;
+ void lockModule() const;
+ void unlockModule() const;
+ void assertModuleLocked() const;
+
+ mutable std::vector<ItemObserver *> m_observers;
+ mutable std::mutex m_observersMutex;
QString m_id;
CodeLocation m_location;
- Item *m_prototype;
- Item *m_scope;
- Item *m_outerItem;
- Item *m_parent;
+ CodePosition m_endPosition;
+ Item *m_prototype = nullptr;
+ Item *m_scope = nullptr;
+ Item *m_outerItem = nullptr;
+ Item *m_parent = nullptr;
QList<Item *> m_children;
FileContextPtr m_file;
PropertyMap m_properties;
@@ -173,10 +222,34 @@ private:
PropertyDeclarationMap m_expiredPropertyDeclarations;
Modules m_modules;
ItemType m_type;
+ mutable std::mutex m_moduleMutex;
+#ifndef NDEBUG
+ mutable std::atomic_bool m_moduleLocked = false;
+#endif
};
inline bool operator<(const Item::Module &m1, const Item::Module &m2) { return m1.name < m2.name; }
+Item *createNonPresentModule(ItemPool &pool, const QString &name, const QString &reason,
+ Item *module);
+void setScopeForDescendants(Item *item, Item *scope);
+
+// This mechanism is needed because Module items are shared between products (not doing so
+// would be prohibitively expensive).
+// The competing accesses are between
+// - Attaching a temporary qbs module for evaluating the Module condition.
+// - Cloning the module when creating an instance.
+// - Directly accessing Module properties, which happens rarely (as opposed to properties of
+// an instance).
+class ModuleItemLocker
+{
+public:
+ ModuleItemLocker(const Item &item) : m_item(item) { item.lockModule(); }
+ ~ModuleItemLocker() { m_item.unlockModule(); }
+private:
+ const Item &m_item;
+};
+
} // namespace Internal
} // namespace qbs