6#include <QtQmlLS/private/qqmllsutils_p.h>
7#include <QtQmlDom/private/qqmldomscriptelements_p.h>
8#include <QtQmlDom/private/qqmldomfieldfilter_p.h>
10#include <QtLanguageServer/private/qlanguageserverprotocol_p.h>
16using namespace
QQmlJS::AST;
17using namespace
QQmlJS::Dom;
50 return int(SemanticTokenTypes::Keyword);
54 return int(SemanticTokenTypes::Operator);
56 return int(SemanticTokenTypes::Type);
60 return int(SemanticTokenTypes::Variable);
62 return int(SemanticTokenTypes::Namespace);
65 return int(SemanticTokenTypes::Property);
68 return int(SemanticTokenTypes::Number);
70 return int(SemanticTokenTypes::Variable);
72 Q_UNREACHABLE_RETURN({});
77 QMultiMap<QString, QString> fieldFilterAdd{};
78 QMultiMap<QString, QString> fieldFilterRemove{
85 return FieldFilter{ fieldFilterAdd, fieldFilterRemove };
89 const std::optional<HighlightsRange> &
range)
90 : m_highlights(highlights), m_range(
range)
96 if (m_range.has_value()) {
100 const auto regions = fLocs->info().regions;
105 switch (
item.internalKind()) {
106 case DomType::Comment: {
107 highlightComment(
item);
110 case DomType::Import: {
111 highlightImport(
item);
114 case DomType::Binding: {
115 highlightBinding(
item);
118 case DomType::Pragma: {
119 highlightPragma(
item);
122 case DomType::EnumDecl: {
123 highlightEnumDecl(
item);
126 case DomType::EnumItem: {
127 highlightEnumItem(
item);
130 case DomType::QmlObject: {
131 highlightQmlObject(
item);
134 case DomType::QmlComponent: {
135 highlightComponent(
item);
138 case DomType::PropertyDefinition: {
139 highlightPropertyDefinition(
item);
142 case DomType::MethodInfo: {
143 highlightMethod(
item);
146 case DomType::ScriptLiteral: {
147 highlightScriptLiteral(
item);
150 case DomType::ScriptIdentifierExpression: {
151 highlightIdentifier(
item);
156 highlightScriptExpressions(
item);
159 Q_UNREACHABLE_RETURN(
false);
162void HighlightingVisitor::highlightComment(
const DomItem &
item)
167 comment->info().comment(), comment->info().sourceLocation());
168 for (
const auto &loc : locs)
169 m_highlights.addHighlight(loc, int(SemanticTokenTypes::
Comment));
172void HighlightingVisitor::highlightImport(
const DomItem &
item)
177 const auto regions = fLocs->info().regions;
178 const auto import = item.as<Import>();
181 if (import->uri.isModule())
193void HighlightingVisitor::highlightBinding(
const DomItem &
item)
199 qCDebug(semanticTokens) <<
"Can't find the locations for" <<
item.internalKind();
202 const auto regions = fLocs->info().regions;
204 if (binding->name().contains(
"."_L1))
207 if (binding->bindingType() != BindingType::Normal) {
216void HighlightingVisitor::highlightPragma(
const DomItem &
item)
221 const auto regions = fLocs->info().regions;
225 for (
auto i = 0;
i < pragma->values.size(); ++
i) {
233void HighlightingVisitor::highlightEnumDecl(
const DomItem &
item)
238 const auto regions = fLocs->info().regions;
243void HighlightingVisitor::highlightEnumItem(
const DomItem &
item)
248 const auto regions = fLocs->info().regions;
254void HighlightingVisitor::highlightQmlObject(
const DomItem &
item)
261 const auto regions = fLocs->info().regions;
263 if (!qmlObject->idStr().isEmpty()) {
268 if (qmlObject->name().contains(
"."_L1))
274void HighlightingVisitor::highlightComponent(
const DomItem &
item)
279 const auto regions = fLocs->info().regions;
284void HighlightingVisitor::highlightPropertyDefinition(
const DomItem &
item)
291 const auto regions = fLocs->info().regions;
294 if (propertyDef->isDefaultMember) {
298 int(SemanticTokenTypes::Keyword));
300 if (propertyDef->isRequired) {
303 int(SemanticTokenTypes::Keyword));
305 if (propertyDef->isReadonly) {
308 int(SemanticTokenTypes::Keyword));
311 if (propertyDef->isAlias())
313 int(SemanticTokenTypes::Keyword));
320void HighlightingVisitor::highlightMethod(
const DomItem &
item)
327 const auto regions = fLocs->info().regions;
328 switch (
method->methodType) {
344 for (
auto i = 0;
i <
method->parameters.size(); ++
i) {
345 DomItem parameter =
item.field(Fields::parameters).index(
i);
348 int(SemanticTokenTypes::Parameter));
354void HighlightingVisitor::highlightScriptLiteral(
const DomItem &
item)
361 const auto regions = fLocs->info().regions;
362 if (std::holds_alternative<QString>(literal->literalValue())) {
363 const QString value = u
'\"' + std::get<QString>(literal->literalValue()) + u
'\"';
366 for (
const auto &loc : locs)
367 m_highlights.addHighlight(loc, int(SemanticTokenTypes::String));
368 }
else if (std::holds_alternative<double>(literal->literalValue()))
370 else if (std::holds_alternative<bool>(literal->literalValue()))
372 else if (std::holds_alternative<std::nullptr_t>(literal->literalValue()))
375 qCWarning(semanticTokens) <<
"Invalid literal variant";
378void HighlightingVisitor::highlightIdentifier(
const DomItem &
item)
383 const auto loc =
id->mainRegionLocation();
390 highlightBySemanticAnalysis(
item, loc);
399 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Variable));
402 switch (expression->type) {
404 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Type));
407 SemanticTokenTypes tokenType = SemanticTokenTypes::Variable;
409 if (
const auto jsIdentifier
410 = expression->semanticScope->jsIdentifier(expression->name.value())) {
411 switch (jsIdentifier.value().kind) {
413 tokenType = SemanticTokenTypes::Parameter;
419 tokenType = SemanticTokenTypes::Variable;
422 if (jsIdentifier.value().isConst) {
427 m_highlights.
addHighlight(loc,
int(tokenType), modifier);
431 if (
const auto scope = expression->semanticScope) {
432 const auto property = scope->property(expression->name.value());
438 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Property), modifier);
443 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Method));
446 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Method));
449 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Method));
452 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Method));
455 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Method));
458 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Variable));
461 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Type));
464 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Enum));
467 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::EnumMember));
470 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Type));
473 m_highlights.
addHighlight(loc,
int(SemanticTokenTypes::Property));
478 .arg(
int(expression->type));
480 Q_UNREACHABLE_RETURN();
483void HighlightingVisitor::highlightScriptExpressions(
const DomItem &
item)
488 const auto regions = fLocs->info().regions;
489 switch (
item.internalKind()) {
490 case DomType::ScriptLiteral:
491 highlightScriptLiteral(
item);
493 case DomType::ScriptForStatement:
496 int(SemanticTokenTypes::Keyword));
499 case DomType::ScriptVariableDeclaration: {
501 int(SemanticTokenTypes::Keyword));
504 case DomType::ScriptReturnStatement:
507 case DomType::ScriptCaseClause:
510 case DomType::ScriptDefaultClause:
513 case DomType::ScriptSwitchStatement:
516 case DomType::ScriptWhileStatement:
519 case DomType::ScriptDoWhileStatement:
523 case DomType::ScriptTryCatchStatement:
528 case DomType::ScriptForEachStatement:
530 int(SemanticTokenTypes::Keyword));
534 case DomType::ScriptThrowStatement:
537 case DomType::ScriptBreakStatement:
540 case DomType::ScriptContinueStatement:
543 case DomType::ScriptIfStatement:
547 case DomType::ScriptLabelledStatement:
550 case DomType::ScriptConditionalExpression:
554 case DomType::ScriptUnaryExpression:
555 case DomType::ScriptPostExpression:
558 case DomType::ScriptType:
564 <<
"Script Expressions with kind" <<
item.internalKind() <<
"not implemented";
567 Q_UNREACHABLE_RETURN();
579QList<QQmlJS::SourceLocation>
583 auto lineBreakLength =
qsizetype(std::char_traits<char>::length(
"\n"));
584 const auto lineLengths = [&lineBreakLength](
QStringView literal) {
585 std::vector<qsizetype> lineLengths;
594 if (
pos - 1 > 0 && literal[
pos - 1] == u
'\r') {
596 lineBreakLength =
qsizetype(std::char_traits<char>::length(
"\r\n"));
600 lineLengths.push_back(
pos - startIndex);
602 startIndex =
pos + lineBreakLength;
603 pos = literal.indexOf(
'\n'_L1, startIndex);
606 if (startIndex < literal.length()) {
607 lineLengths.push_back(literal.length() - startIndex);
612 QList<QQmlJS::SourceLocation>
result;
616 for (
const auto lineLength : lineLengths(stringLiteral)) {
617 lineLoc.
length = lineLength;
618 result.push_back(lineLoc);
621 lineLoc.offset += lineLoc.length + lineBreakLength;
623 lineLoc.startColumn = 1;
631 const auto highlightingTokens = highlights.
highlights();
632 constexpr auto tokenEncodingLength = 5;
633 result.reserve(tokenEncodingLength * highlightingTokens.size());
638 std::for_each(highlightingTokens.constBegin(), highlightingTokens.constEnd(), [&](
const auto &
token) {
639 Q_ASSERT(token.startLine >= prevLine);
640 if (token.startLine != prevLine)
642 result.emplace_back(token.startLine - prevLine);
643 result.emplace_back(token.startColumn - prevColumn);
644 result.emplace_back(token.length);
645 result.emplace_back(token.tokenType);
646 result.emplace_back(token.tokenModifier);
647 prevLine = token.startLine;
648 prevColumn = token.startColumn;
668 *baseModifier |= (1 << int(modifier));
678 int startOffsetItem = int(loc.
offset);
679 int endOffsetItem = startOffsetItem + int(loc.
length);
680 return (startOffsetItem <=
r.endOffset) && (
r.startOffset <= endOffsetItem);
689 int length = resultID.length();
691 if (resultID[
i] ==
'9') {
694 resultID[
i] = resultID[
i] + 1;
698 resultID.prepend(
'1');
710 const auto [oldStart, newStart] =
711 std::mismatch(oldData.cbegin(), oldData.cend(), newData.cbegin(), newData.cend());
715 const auto [
r1,
r2] = std::mismatch(oldData.crbegin(), std::make_reverse_iterator(oldStart),
716 newData.crbegin(), std::make_reverse_iterator(newStart));
717 const auto oldEnd =
r1.base();
718 const auto newEnd =
r2.base();
721 if (oldStart == oldEnd && newStart == newEnd)
724 SemanticTokensEdit
edit;
725 edit.start = int(std::distance(newData.cbegin(), newStart));
726 edit.deleteCount = int(std::distance(oldStart, oldEnd));
728 if (newStart >= newData.cbegin() && newEnd <= newData.cend() && newStart < newEnd)
729 edit.data.emplace(newStart, newEnd);
731 return { std::move(
edit) };
738 qCDebug(semanticTokens) <<
"Invalid locations: Cannot add highlight to token";
743 m_highlights.
insert(loc.
offset, QT_PREPEND_NAMESPACE(
Token)(loc, tokenType, tokenModifier));
749 if (!regions.contains(region)) {
750 qCDebug(semanticTokens) <<
"Invalid region: Cannot add highlight to token";
754 const auto loc = regions.value(region);
759 const std::optional<HighlightsRange> &
range)
HighlightingVisitor(Highlights &highlights, const std::optional< HighlightsRange > &range)
bool operator()(QQmlJS::Dom::Path, const QQmlJS::Dom::DomItem &item, bool)
void addHighlight(const QQmlJS::SourceLocation &loc, int tokenType, int tokenModifier=0)
QList< int > collectTokens(const QQmlJS::Dom::DomItem &item, const std::optional< HighlightsRange > &range)
HighlightsContainer & highlights()
iterator insert(const Key &key, const T &value)
bool contains(const Key &key) const
static FileLocations::Tree treeOf(const DomItem &)
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString fromUtf16(const char16_t *, qsizetype size=-1)
@ QuestionMarkTokenRegion
bool emptyChildrenVisitor(Path, const DomItem &, bool)
std::optional< ExpressionType > resolveExpressionType(const QQmlJS::Dom::DomItem &item, ResolveOptions options)
@ EnumeratorValueIdentifier
@ GroupedPropertyIdentifier
@ PropertyChangedHandlerIdentifier
@ PropertyChangedSignalIdentifier
@ SignalHandlerIdentifier
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum GLuint GLenum GLsizei length
static int tokenTypeFromRegion(QQmlJS::Dom::FileLocationRegion region)
static FieldFilter highlightingFilter()
static QList< QQmlJS::SourceLocation > sourceLocationsFromMultiLineToken(QStringView code, const QQmlJS::SourceLocation &tokenLocation)
Returns multiple source locations for a given raw comment.
static QList< int > encodeSemanticTokens(Highlights &highlights)
static void updateResultID(QByteArray &resultID)
static QList< QLspSpecification::SemanticTokensEdit > computeDiff(const QList< int > &, const QList< int > &)
static bool rangeOverlapsWithSourceLocation(const QQmlJS::SourceLocation &loc, const HighlightsRange &r)
static void addModifier(QLspSpecification::SemanticTokenModifiers modifier, int *baseModifier)