diff options
Diffstat (limited to 'src/lib/corelib/language/item.h')
-rw-r--r-- | src/lib/corelib/language/item.h | 125 |
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 ¶meters) + : dependsItem(dependsItem), parameters(parameters) {} + LoadContext(Item *dependsItem, ParametersWithPriority &¶meters) + : 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 ¶meters, + Logger &logger); + void overrideProperties( + const QVariantMap &config, const QualifiedId &namePrefix, const SetupProjectParameters ¶meters, 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 |