1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLSEMANTICTOKENS_P_H
5#define QQMLSEMANTICTOKENS_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 <QtLanguageServer/private/qlanguageserverspec_p.h>
19#include <QtQmlDom/private/qqmldomitem_p.h>
20#include <QtCore/qlist.h>
21#include <QtCore/qmap.h>
22
23QT_BEGIN_NAMESPACE
24
25Q_DECLARE_LOGGING_CATEGORY(semanticTokens)
26
27namespace HighlightingUtils {
28Q_NAMESPACE
29
30// Protocol agnostic highlighting kinds
31// Use this enum while visiting dom tree to define the highlighting kinds for the semantic tokens
32// Then map it to the protocol specific token types and modifiers
33// This can be as much as detailed as needed
34enum class QmlHighlightKind {
35 QmlKeyword, // Qml keyword
36 QmlType, // Qml type name
37 QmlImportId, // Qml import module name
38 QmlNamespace, // Qml module namespace, i.e import QtQuick as Namespace
39 QmlLocalId, // Object id within the same file
40 QmlExternalId, // Object id defined in another file. [UNUSED FOR NOW]
41 QmlProperty, // Qml property. For now used for all kind of properties
42 QmlScopeObjectProperty, // Qml property defined in the current scope
43 QmlRootObjectProperty, // Qml property defined in the parent scopes
44 QmlExternalObjectProperty, // Qml property defined in the root object of another file
45 QmlMethod,
46 QmlMethodParameter,
47 QmlSignal,
48 QmlSignalHandler,
49 QmlEnumName, // Enum type name
50 QmlEnumMember, // Enum field names
51 QmlPragmaName, // Qml pragma name
52 QmlPragmaValue, // Qml pragma value
53 QmlTypeModifier, // list<QtObject>, list is the modifier, QtObject is the type
54 JsImport, // Js imported name
55 JsGlobalVar, // Js global variable or objects
56 JsGlobalMethod, // Js global method
57 JsScopeVar, // Js variable defined in the current scope
58 JsLabel, // js label
59 Number,
60 String,
61 Comment,
62 Operator,
63 Unknown, // Used for the unknown tokens
64};
65
66enum class QmlHighlightModifier {
67 None = 0,
68 QmlPropertyDefinition = 1 << 0,
69 QmlDefaultProperty = 1 << 1,
70 QmlRequiredProperty = 1 << 2,
71 QmlReadonlyProperty = 1 << 3,
72};
73Q_DECLARE_FLAGS(QmlHighlightModifiers, QmlHighlightModifier)
74Q_DECLARE_OPERATORS_FOR_FLAGS(QmlHighlightModifiers)
75
76enum class HighlightingMode { Default, QtCHighlighting };
77
78// Protocol specific token types
79// The values in this enum are converted to relevant strings and sent to the client as server
80// capabilities The convention is that the first letter in the enum value is decapitalized and the
81// rest is unchanged i.e Namespace -> "namespace" This is handled in enumToByteArray() helper
82// function.
83enum class SemanticTokenProtocolTypes {
84 // Subset of the QLspSpefication::SemanticTokenTypes enum
85 // We register only the token types used in the qml semantic highlighting
86 Namespace,
87 Type,
88 Enum,
89 Parameter,
90 Variable,
91 Property,
92 EnumMember,
93 Method,
94 Keyword,
95 Comment,
96 String,
97 Number,
98 Regexp,
99 Operator,
100 Decorator,
101
102 // Additional token types for the extended semantic highlighting
103 QmlLocalId, // object id within the same file
104 QmlExternalId, // object id defined in another file
105 QmlRootObjectProperty, // qml property defined in the parent scopes
106 QmlScopeObjectProperty, // qml property defined in the current scope
107 QmlExternalObjectProperty, // qml property defined in the root object of another file
108 JsScopeVar, // js variable defined in the current file
109 JsImportVar, // js import name that is imported in the qml file
110 JsGlobalVar, // js global variables
111 QmlStateName, // name of a qml state
112};
113Q_ENUM_NS(SemanticTokenProtocolTypes)
114
115} // namespace HighlightingUtils
116
117// Represents a semantic highlighting token
118// startLine and startColumn are 0-based as in LSP spec.
119struct Token
120{
121 Token() = default;
122 Token(const QQmlJS::SourceLocation &loc, int tokenType, int tokenModifier = 0)
123 : offset(loc.offset),
124 length(loc.length),
125 startLine(loc.startLine - 1),
126 startColumn(loc.startColumn - 1),
127 tokenType(tokenType),
128 tokenModifier(tokenModifier)
129 {
130 }
131
132 inline friend bool operator<(const Token &lhs, const Token &rhs)
133 {
134 return lhs.offset < rhs.offset;
135 }
136
137 inline friend bool operator==(const Token &lhs, const Token &rhs)
138 {
139 return lhs.offset == rhs.offset && lhs.length == rhs.length
140 && lhs.startLine == rhs.startLine && lhs.startColumn == rhs.startColumn
141 && lhs.tokenType == rhs.tokenType && lhs.tokenModifier == rhs.tokenModifier;
142 }
143
144 int offset;
145 int length;
146 int startLine;
147 int startColumn;
148 int tokenType;
149 int tokenModifier;
150};
151
152using HighlightsContainer = QMap<int, QT_PREPEND_NAMESPACE(Token)>;
153
154/*!
155\internal
156Offsets start from zero.
157*/
158struct HighlightsRange
159{
160 int startOffset;
161 int endOffset;
162};
163
164class Highlights
165{
166public:
167 using QmlHighlightKindToLspKind = int (*)(HighlightingUtils::QmlHighlightKind);
168 Highlights(HighlightingUtils::HighlightingMode mode = HighlightingUtils::HighlightingMode::Default);
169 void addHighlight(const QQmlJS::SourceLocation &loc, HighlightingUtils::QmlHighlightKind,
170 HighlightingUtils::QmlHighlightModifiers =
171 HighlightingUtils::QmlHighlightModifier::None);
172 HighlightsContainer &highlights() { return m_highlights; }
173 const HighlightsContainer &highlights() const { return m_highlights; }
174
175private:
176 void addHighlightImpl(const QQmlJS::SourceLocation &loc, int tokenType, int tokenModifier = 0);
177 HighlightsContainer m_highlights;
178 QmlHighlightKindToLspKind m_mapToProtocol;
179};
180
181namespace HighlightingUtils
182{
183 QList<int> encodeSemanticTokens(Highlights &highlights);
184 QList<QQmlJS::SourceLocation>
185 sourceLocationsFromMultiLineToken(QStringView code,
186 const QQmlJS::SourceLocation &tokenLocation);
187 void addModifier(QLspSpecification::SemanticTokenModifiers modifier, int *baseModifier);
188 bool rangeOverlapsWithSourceLocation(const QQmlJS::SourceLocation &loc, const HighlightsRange &r);
189 QList<QLspSpecification::SemanticTokensEdit> computeDiff(const QList<int> &, const QList<int> &);
190 void updateResultID(QByteArray &resultID);
191 QList<int> collectTokens(const QQmlJS::Dom::DomItem &item,
192 const std::optional<HighlightsRange> &range,
193 HighlightingMode mode = HighlightingMode::Default);
194} // namespace HighlightingUtils
195
196class HighlightingVisitor
197{
198public:
199 HighlightingVisitor(Highlights &highlights, const std::optional<HighlightsRange> &range);
200 bool operator()(QQmlJS::Dom::Path, const QQmlJS::Dom::DomItem &item, bool);
201
202private:
203 void highlightComment(const QQmlJS::Dom::DomItem &item);
204 void highlightImport(const QQmlJS::Dom::DomItem &item);
205 void highlightBinding(const QQmlJS::Dom::DomItem &item);
206 void highlightPragma(const QQmlJS::Dom::DomItem &item);
207 void highlightEnumItem(const QQmlJS::Dom::DomItem &item);
208 void highlightEnumDecl(const QQmlJS::Dom::DomItem &item);
209 void highlightQmlObject(const QQmlJS::Dom::DomItem &item);
210 void highlightComponent(const QQmlJS::Dom::DomItem &item);
211 void highlightPropertyDefinition(const QQmlJS::Dom::DomItem &item);
212 void highlightMethod(const QQmlJS::Dom::DomItem &item);
213 void highlightScriptLiteral(const QQmlJS::Dom::DomItem &item);
214 void highlightIdentifier(const QQmlJS::Dom::DomItem &item);
215 void highlightBySemanticAnalysis(const QQmlJS::Dom::DomItem &item, QQmlJS::SourceLocation loc);
216 void highlightScriptExpressions(const QQmlJS::Dom::DomItem &item);
217
218private:
219 Highlights &m_highlights;
220 std::optional<HighlightsRange> m_range;
221};
222
223QT_END_NAMESPACE
224
225#endif // QQMLSEMANTICTOKENS_P_H
226

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/qmlls/qqmlsemantictokens_p.h