1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#ifndef QQMLJSSCOPESBYID_P_H
5#define QQMLJSSCOPESBYID_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16
17
18#include "qqmljsscope_p.h"
19
20#include <QtCore/qhash.h>
21#include <QtCore/qstring.h>
22
23QT_BEGIN_NAMESPACE
24
25class QQmlJSScopesById
26{
27public:
28 bool componentsAreBound() const { return m_componentsAreBound; }
29 void setComponentsAreBound(bool bound) { m_componentsAreBound = bound; }
30
31 void setSignaturesAreEnforced(bool enforced) { m_signaturesAreEnforced = enforced; }
32 bool signaturesAreEnforced() const { return m_signaturesAreEnforced; }
33
34 void setValueTypesAreAddressable(bool addressable) { m_valueTypesAreAddressable = addressable; }
35 bool valueTypesAreAddressable() const { return m_valueTypesAreAddressable; }
36
37 QString id(const QQmlJSScope::ConstPtr &scope, const QQmlJSScope::ConstPtr &referrer) const
38 {
39 const QQmlJSScope::ConstPtr referrerRoot = componentRoot(inner: referrer);
40 for (auto it = m_scopesById.begin(), end = m_scopesById.end(); it != end; ++it) {
41 if (*it == scope && isComponentVisible(observed: componentRoot(inner: *it), observer: referrerRoot))
42 return it.key();
43 }
44 return QString();
45 }
46
47 /*!
48 \internal
49 Returns the scope that has id \a id in the component to which \a referrer belongs to.
50 If no such scope exists, a null scope is returned.
51 */
52 QQmlJSScope::ConstPtr scope(const QString &id, const QQmlJSScope::ConstPtr &referrer) const
53 {
54 Q_ASSERT(!id.isEmpty());
55 const auto range = m_scopesById.equal_range(key: id);
56 if (range.first == range.second)
57 return QQmlJSScope::ConstPtr();
58 const QQmlJSScope::ConstPtr referrerRoot = componentRoot(inner: referrer);
59
60 for (auto it = range.first; it != range.second; ++it) {
61 if (isComponentVisible(observed: componentRoot(inner: *it), observer: referrerRoot))
62 return *it;
63 }
64
65 return QQmlJSScope::ConstPtr();
66 }
67
68 void insert(const QString &id, const QQmlJSScope::ConstPtr &scope)
69 {
70 Q_ASSERT(!id.isEmpty());
71 m_scopesById.insert(key: id, value: scope);
72 }
73
74 void clear() { m_scopesById.clear(); }
75
76 /*!
77 \internal
78 Returns \c true if \a id exists anywhere in the current document.
79 This is still allowed if the other occurrence is in a different (inline) component.
80 Check the return value of scope to know whether the id has already been assigned
81 in a givne scope.
82 */
83 bool existsAnywhereInDocument(const QString &id) const { return m_scopesById.contains(key: id); }
84
85private:
86 static QQmlJSScope::ConstPtr componentRoot(const QQmlJSScope::ConstPtr &inner)
87 {
88 QQmlJSScope::ConstPtr scope = inner;
89 while (scope && !scope->isComponentRootElement() && !scope->isInlineComponent()) {
90 if (QQmlJSScope::ConstPtr parent = scope->parentScope())
91 scope = parent;
92 else
93 break;
94 }
95 return scope;
96 }
97
98 bool isComponentVisible(
99 const QQmlJSScope::ConstPtr &observed, const QQmlJSScope::ConstPtr &observer) const
100 {
101 if (!m_componentsAreBound)
102 return observed == observer;
103
104 for (QQmlJSScope::ConstPtr scope = observer; scope; scope = scope->parentScope()) {
105 if (scope == observed)
106 return true;
107 }
108
109 return false;
110 }
111
112 QMultiHash<QString, QQmlJSScope::ConstPtr> m_scopesById;
113 bool m_componentsAreBound = false;
114 bool m_signaturesAreEnforced = true;
115 bool m_valueTypesAreAddressable = false;
116};
117
118QT_END_NAMESPACE
119
120#endif // QQMLJSSCOPESBYID_P_H
121

source code of qtdeclarative/src/qmlcompiler/qqmljsscopesbyid_p.h