5#include <qqmlsemantictokens_p.h>
7#include <QtQmlLS/private/qqmllsutils_p.h>
8#include <QtQmlDom/private/qqmldomscriptelements_p.h>
9#include <QtQmlDom/private/qqmldomfieldfilter_p.h>
11#include <QtLanguageServer/private/qlanguageserverprotocol_p.h>
15Q_LOGGING_CATEGORY(semanticTokens,
"qt.languageserver.semanticTokens")
17using namespace QQmlJS::AST;
18using namespace QQmlJS::Dom;
19using namespace QLspSpecification;
24 switch (highlightKind) {
89 switch (highlightKind) {
149
150
151
152
153
154
159 static QSet<QString> noConstructorObjects = { u"Math"_s, u"JSON"_s, u"Atomics"_s, u"Reflect"_s,
163 if (noConstructorObjects.contains(name))
166 if (item.directParent().internalKind() == DomType::ScriptNewMemberExpression) {
169 if (DomItem containingCallExpression = item.filterUp(
170 [](DomType k,
const DomItem &) {
return k == DomType::ScriptCallExpression; },
171 FilterUpOptions::ReturnOuter)) {
174 const auto callee = containingCallExpression.field(Fields::callee);
175 if (callee.internalKind() == DomType::ScriptBinaryExpression) {
176 const auto right = callee.field(Fields::right);
177 if (right.internalKind() == DomType::ScriptIdentifierExpression
178 && right.field(Fields::identifier).value().toString() == name) {
192 using namespace QLspSpecification;
196 if (highlightModifier.testFlag(QmlHighlightModifier::QmlPropertyDefinition))
197 addModifier(SemanticTokenModifiers::Definition, &modifier);
199 if (highlightModifier.testFlag(QmlHighlightModifier::QmlDefaultProperty))
200 addModifier(SemanticTokenModifiers::DefaultLibrary, &modifier);
202 if (highlightModifier.testFlag(QmlHighlightModifier::QmlFinalProperty))
203 addModifier(SemanticTokenModifiers::Static, &modifier);
205 if (highlightModifier.testFlag(QmlHighlightModifier::QmlRequiredProperty))
206 addModifier(SemanticTokenModifiers::Abstract, &modifier);
208 if (highlightModifier.testFlag(QmlHighlightModifier::QmlReadonlyProperty))
209 addModifier(SemanticTokenModifiers::Readonly, &modifier);
216 QMultiMap<QString, QString> fieldFilterAdd{};
217 QMultiMap<QString, QString> fieldFilterRemove{
218 { QString(), Fields::propertyInfos.toString() },
219 { QString(), Fields::fileLocationsTree.toString() },
220 { QString(), Fields::importScope.toString() },
221 { QString(), Fields::defaultPropertyName.toString() },
222 { QString(), Fields::get.toString() },
224 return FieldFilter{ fieldFilterAdd, fieldFilterRemove };
228 const std::optional<HighlightsRange> &range,
229 HighlightingMode mode)
234 [
this](
const Path &path,
const DomItem &item,
bool b) {
235 return this->visitor(path, item, b);
237 VisitOption::Default | VisitOption::NoPath, emptyChildrenVisitor, emptyChildrenVisitor,
238 highlightingFilter());
243 if (m_range.has_value()) {
244 const auto fLocs = FileLocations::treeOf(item);
247 const auto regions = fLocs->info().regions;
248 if (!HighlightingUtils::rangeOverlapsWithSourceLocation(regions[MainRegion],
252 switch (item.internalKind()) {
253 case DomType::Comment: {
254 highlightComment(item);
257 case DomType::Import: {
258 highlightImport(item);
261 case DomType::Binding: {
262 highlightBinding(item);
265 case DomType::Pragma: {
266 highlightPragma(item);
269 case DomType::EnumDecl: {
270 highlightEnumDecl(item);
273 case DomType::EnumItem: {
274 highlightEnumItem(item);
277 case DomType::QmlObject: {
278 highlightQmlObject(item);
281 case DomType::QmlComponent: {
282 highlightComponent(item);
285 case DomType::PropertyDefinition: {
286 highlightPropertyDefinition(item);
289 case DomType::MethodInfo: {
290 highlightMethod(item);
293 case DomType::ScriptLiteral: {
294 highlightScriptLiteral(item);
297 case DomType::ScriptCallExpression: {
298 highlightCallExpression(item);
301 case DomType::ScriptIdentifierExpression: {
302 highlightIdentifier(item);
306 if (item.ownerAs<ScriptExpression>())
307 highlightScriptExpressions(item);
310 Q_UNREACHABLE_RETURN(
false);
315 const auto comment = item.as<Comment>();
317 const auto locs = HighlightingUtils::sourceLocationsFromMultiLineToken(
318 comment->info().comment(), comment->info().sourceLocation());
319 for (
const auto &loc : locs)
320 m_highlights.addHighlight(loc, QmlHighlightKind::Comment);
325 const auto fLocs = FileLocations::treeOf(item);
328 const auto regions = fLocs->info().regions;
329 const auto import = item.as<Import>();
331 m_highlights.addHighlight(regions[ImportTokenRegion], QmlHighlightKind::QmlKeyword);
332 if (import->uri.isModule())
333 m_highlights.addHighlight(regions[ImportUriRegion], QmlHighlightKind::QmlImportId);
335 m_highlights.addHighlight(regions[ImportUriRegion], QmlHighlightKind::String);
336 if (regions.contains(VersionRegion))
337 m_highlights.addHighlight(regions[VersionRegion], QmlHighlightKind::Number);
338 if (regions.contains(AsTokenRegion)) {
339 m_highlights.addHighlight(regions[AsTokenRegion], QmlHighlightKind::QmlKeyword);
340 m_highlights.addHighlight(regions[IdNameRegion], QmlHighlightKind::QmlNamespace);
346 const auto binding = item.as<Binding>();
348 const auto fLocs = FileLocations::treeOf(item);
350 qCDebug(semanticTokens) <<
"Can't find the locations for" << item.internalKind();
353 const auto regions = fLocs->info().regions;
355 if (binding->name().contains(
"."_L1))
358 if (binding->bindingType() != BindingType::Normal) {
359 m_highlights.addHighlight(regions[OnTokenRegion], QmlHighlightKind::QmlKeyword);
360 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlProperty);
364 return m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlProperty);
369 const auto fLocs = FileLocations::treeOf(item);
372 const auto regions = fLocs->info().regions;
373 m_highlights.addHighlight(regions[PragmaKeywordRegion], QmlHighlightKind::QmlKeyword);
374 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlPragmaName );
375 const auto pragma = item.as<Pragma>();
376 for (
auto i = 0; i < pragma->values.size(); ++i) {
377 DomItem value = item.field(Fields::values).index(i);
378 const auto valueRegions = FileLocations::treeOf(value)->info().regions;
379 m_highlights.addHighlight(valueRegions[PragmaValuesRegion], QmlHighlightKind::QmlPragmaValue);
386 const auto fLocs = FileLocations::treeOf(item);
389 const auto regions = fLocs->info().regions;
390 m_highlights.addHighlight(regions[EnumKeywordRegion], QmlHighlightKind::QmlKeyword);
391 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlEnumName);
396 const auto fLocs = FileLocations::treeOf(item);
399 const auto regions = fLocs->info().regions;
400 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlEnumMember);
401 if (regions.contains(EnumValueRegion))
402 m_highlights.addHighlight(regions[EnumValueRegion], QmlHighlightKind::Number);
407 const auto qmlObject = item.as<QmlObject>();
409 const auto fLocs = FileLocations::treeOf(item);
412 const auto regions = fLocs->info().regions;
414 if (!qmlObject->idStr().isEmpty()) {
415 m_highlights.addHighlight(regions[IdTokenRegion], QmlHighlightKind::QmlProperty);
416 m_highlights.addHighlight(regions[IdNameRegion], QmlHighlightKind::QmlLocalId);
419 if (qmlObject->name().contains(
"."_L1))
422 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlType);
427 const auto fLocs = FileLocations::treeOf(item);
430 const auto regions = fLocs->info().regions;
431 const auto componentKeywordIt = regions.constFind(ComponentKeywordRegion);
432 if (componentKeywordIt == regions.constEnd())
434 m_highlights.addHighlight(*componentKeywordIt, QmlHighlightKind::QmlKeyword);
435 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlType);
440 const auto propertyDef = item.as<PropertyDefinition>();
441 Q_ASSERT(propertyDef);
442 const auto fLocs = FileLocations::treeOf(item);
445 const auto regions = fLocs->info().regions;
447 if (propertyDef->isDefaultMember) {
449 m_highlights.addHighlight(regions[DefaultKeywordRegion], QmlHighlightKind::QmlKeyword);
451 if (propertyDef->isFinal) {
453 m_highlights.addHighlight(regions[FinalKeywordRegion], QmlHighlightKind::QmlKeyword);
455 if (propertyDef->isRequired) {
457 m_highlights.addHighlight(regions[RequiredKeywordRegion], QmlHighlightKind::QmlKeyword);
459 if (propertyDef->isReadonly) {
461 m_highlights.addHighlight(regions[ReadonlyKeywordRegion], QmlHighlightKind::QmlKeyword);
463 m_highlights.addHighlight(regions[PropertyKeywordRegion], QmlHighlightKind::QmlKeyword);
464 if (propertyDef->isAlias())
465 m_highlights.addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlKeyword);
467 m_highlights.addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
469 m_highlights.addHighlight(regions[TypeModifierRegion], QmlHighlightKind::QmlTypeModifier);
470 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlProperty,
476 const auto method = item.as<MethodInfo>();
478 const auto fLocs = FileLocations::treeOf(item);
481 const auto regions = fLocs->info().regions;
482 switch (method->methodType) {
483 case MethodInfo::Signal: {
484 m_highlights.addHighlight(regions[SignalKeywordRegion], QmlHighlightKind::QmlKeyword);
485 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlMethod);
488 case MethodInfo::Method: {
489 m_highlights.addHighlight(regions[FunctionKeywordRegion], QmlHighlightKind::QmlKeyword);
490 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlMethod);
491 m_highlights.addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
498 for (
auto i = 0; i < method->parameters.size(); ++i) {
499 DomItem parameter = item.field(Fields::parameters).index(i);
500 const auto paramRegions = FileLocations::treeOf(parameter)->info().regions;
501 m_highlights.addHighlight(paramRegions[IdentifierRegion],
502 QmlHighlightKind::QmlMethodParameter);
503 m_highlights.addHighlight(paramRegions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
510 const auto literal = item.as<ScriptElements::Literal>();
512 const auto fLocs = FileLocations::treeOf(item);
515 const auto regions = fLocs->info().regions;
516 if (std::holds_alternative<QString>(literal->literalValue())) {
517 const auto file = item.containingFile().as<QmlFile>();
520 const auto &code = file->engine()->code();
521 const auto offset = regions[MainRegion].offset;
522 const auto length = regions[MainRegion].length;
523 const QStringView literalCode = QStringView{code}.mid(offset, length);
524 const auto &locs = HighlightingUtils::sourceLocationsFromMultiLineToken(
525 literalCode, regions[MainRegion]);
526 for (
const auto &loc : locs)
527 m_highlights.addHighlight(loc, QmlHighlightKind::String);
528 }
else if (std::holds_alternative<
double>(literal->literalValue()))
529 m_highlights.addHighlight(regions[MainRegion], QmlHighlightKind::Number);
530 else if (std::holds_alternative<
bool>(literal->literalValue()))
531 m_highlights.addHighlight(regions[MainRegion], QmlHighlightKind::QmlKeyword);
532 else if (std::holds_alternative<std::nullptr_t>(literal->literalValue()))
533 m_highlights.addHighlight(regions[MainRegion], QmlHighlightKind::QmlKeyword);
535 qCWarning(semanticTokens) <<
"Invalid literal variant";
540 using namespace QLspSpecification;
541 const auto id = item.as<ScriptElements::IdentifierExpression>();
543 const auto loc = id->mainRegionLocation();
547 if (m_highlights.tokens().contains(loc.offset))
553 if (QQmlLSUtils::isFieldMemberAccess(item))
554 highlightFieldMemberAccess(item, loc);
556 highlightBySemanticAnalysis(item, loc);
561 const auto highlight = [
this](
const DomItem &item) {
562 if (item.internalKind() == DomType::ScriptIdentifierExpression) {
563 const auto id = item.as<ScriptElements::IdentifierExpression>();
565 const auto loc = id->mainRegionLocation();
566 m_highlights.addHighlight(loc, QmlHighlightKind::QmlMethod);
570 if (item.internalKind() == DomType::ScriptCallExpression) {
572 const auto callee = item.field(Fields::callee);
573 if (callee.internalKind() == DomType::ScriptIdentifierExpression) {
576 }
else if (callee.internalKind() == DomType::ScriptBinaryExpression) {
578 const auto right = callee.field(Fields::right);
579 if (right.internalKind() == DomType::ScriptIdentifierExpression)
587 QQmlJS::SourceLocation loc)
591 const auto name = item.field(Fields::identifier).value().toString();
592 if (!name.isEmpty() && name.at(0).category() == QChar::Letter_Uppercase) {
595 return highlightBySemanticAnalysis(item, loc);
598 const auto expression =
599 QQmlLSUtils::resolveExpressionType(item, QQmlLSUtils::ResolveOptions::ResolveOwnerType);
602 m_highlights.addHighlight(loc, QmlHighlightKind::Field);
606 if (expression->type == QQmlLSUtils::MethodIdentifier
607 || expression->type == QQmlLSUtils::LambdaMethodIdentifier) {
608 m_highlights.addHighlight(loc, QmlHighlightKind::QmlMethod);
611 return m_highlights.addHighlight(loc, QmlHighlightKind::Field);
615void HighlightingVisitor::highlightBySemanticAnalysis(
const DomItem &item, QQmlJS::SourceLocation loc)
617 const auto expression = QQmlLSUtils::resolveExpressionType(
618 item, QQmlLSUtils::ResolveOptions::ResolveOwnerType);
621 m_highlights.addHighlight(loc, QmlHighlightKind::Unknown);
624 switch (expression->type) {
625 case QQmlLSUtils::QmlComponentIdentifier:
626 m_highlights.addHighlight(loc, QmlHighlightKind::QmlType);
628 case QQmlLSUtils::JavaScriptIdentifier: {
631 if (
const auto scope = expression->semanticScope) {
632 if (
const auto jsIdentifier = scope->jsIdentifier(*expression->name)) {
633 if (jsIdentifier->kind == QQmlJSScope::JavaScriptIdentifier::Parameter)
635 if (jsIdentifier->isConst) {
638 m_highlights.addHighlight(loc, tokenType, modifier);
642 if (
const auto name = expression->name) {
643 if (
const auto highlightKind = resolveJsGlobalObjectKind(item, *name))
644 return m_highlights.addHighlight(loc, *highlightKind);
648 case QQmlLSUtils::PropertyIdentifier: {
649 if (
const auto scope = expression->semanticScope) {
651 if (scope == item.qmlObject().semanticScope()) {
653 }
else if (scope == item.rootQmlObject(GoTo::MostLikely).semanticScope()) {
658 const auto property = scope->property(expression->name.value());
660 if (!property.isWritable())
662 m_highlights.addHighlight(loc, tokenType, modifier);
666 case QQmlLSUtils::PropertyChangedSignalIdentifier:
667 m_highlights.addHighlight(loc, QmlHighlightKind::QmlSignal);
669 case QQmlLSUtils::PropertyChangedHandlerIdentifier:
670 m_highlights.addHighlight(loc, QmlHighlightKind::QmlSignalHandler);
672 case QQmlLSUtils::SignalIdentifier:
673 m_highlights.addHighlight(loc, QmlHighlightKind::QmlSignal);
675 case QQmlLSUtils::SignalHandlerIdentifier:
676 m_highlights.addHighlight(loc, QmlHighlightKind::QmlSignalHandler);
678 case QQmlLSUtils::MethodIdentifier:
679 m_highlights.addHighlight(loc, QmlHighlightKind::QmlMethod);
681 case QQmlLSUtils::QmlObjectIdIdentifier: {
682 const auto qmlfile = item.fileObject().as<QmlFile>();
684 m_highlights.addHighlight(loc, QmlHighlightKind::Unknown);
687 const auto resolver = qmlfile->typeResolver();
689 m_highlights.addHighlight(loc, QmlHighlightKind::Unknown);
692 const auto &objects = resolver->objectsById();
693 if (expression->name.has_value()) {
694 const auto &name = expression->name.value();
695 const auto boundName =
696 objects.id(expression->semanticScope, item.qmlObject().semanticScope());
697 if (!boundName.isEmpty() && name == boundName) {
699 m_highlights.addHighlight(loc, QmlHighlightKind::QmlLocalId);
702 m_highlights.addHighlight(loc, QmlHighlightKind::QmlExternalId);
706 m_highlights.addHighlight(loc, QmlHighlightKind::QmlExternalId);
710 case QQmlLSUtils::SingletonIdentifier:
711 m_highlights.addHighlight(loc, QmlHighlightKind::QmlType);
713 case QQmlLSUtils::EnumeratorIdentifier:
714 m_highlights.addHighlight(loc, QmlHighlightKind::QmlEnumName);
716 case QQmlLSUtils::EnumeratorValueIdentifier:
717 m_highlights.addHighlight(loc, QmlHighlightKind::QmlEnumMember);
719 case QQmlLSUtils::AttachedTypeIdentifier:
720 case QQmlLSUtils::AttachedTypeIdentifierInBindingTarget:
721 m_highlights.addHighlight(loc, QmlHighlightKind::QmlType);
723 case QQmlLSUtils::GroupedPropertyIdentifier:
724 m_highlights.addHighlight(loc, QmlHighlightKind::QmlProperty);
726 case QQmlLSUtils::QualifiedModuleIdentifier:
727 m_highlights.addHighlight(loc, QmlHighlightKind::QmlNamespace);
730 qCWarning(semanticTokens)
731 << QString::fromLatin1(
"Semantic token for %1 has not been implemented yet")
732 .arg(
int(expression->type));
738 const auto fLocs = FileLocations::treeOf(item);
741 const auto regions = fLocs->info().regions;
742 switch (item.internalKind()) {
743 case DomType::ScriptLiteral:
744 highlightScriptLiteral(item);
746 case DomType::ScriptForStatement:
747 m_highlights.addHighlight(regions[ForKeywordRegion], QmlHighlightKind::QmlKeyword);
748 m_highlights.addHighlight(regions[TypeIdentifierRegion],
749 QmlHighlightKind::QmlKeyword);
752 case DomType::ScriptVariableDeclaration: {
753 m_highlights.addHighlight(regions[TypeIdentifierRegion],
754 QmlHighlightKind::QmlKeyword);
757 case DomType::ScriptReturnStatement:
758 m_highlights.addHighlight(regions[ReturnKeywordRegion], QmlHighlightKind::QmlKeyword);
760 case DomType::ScriptCaseClause:
761 m_highlights.addHighlight(regions[CaseKeywordRegion], QmlHighlightKind::QmlKeyword);
763 case DomType::ScriptDefaultClause:
764 m_highlights.addHighlight(regions[DefaultKeywordRegion], QmlHighlightKind::QmlKeyword);
766 case DomType::ScriptSwitchStatement:
767 m_highlights.addHighlight(regions[SwitchKeywordRegion], QmlHighlightKind::QmlKeyword);
769 case DomType::ScriptWhileStatement:
770 m_highlights.addHighlight(regions[WhileKeywordRegion], QmlHighlightKind::QmlKeyword);
772 case DomType::ScriptDoWhileStatement:
773 m_highlights.addHighlight(regions[DoKeywordRegion], QmlHighlightKind::QmlKeyword);
774 m_highlights.addHighlight(regions[WhileKeywordRegion], QmlHighlightKind::QmlKeyword);
776 case DomType::ScriptTryCatchStatement:
777 m_highlights.addHighlight(regions[TryKeywordRegion], QmlHighlightKind::QmlKeyword);
778 m_highlights.addHighlight(regions[CatchKeywordRegion], QmlHighlightKind::QmlKeyword);
779 m_highlights.addHighlight(regions[FinallyKeywordRegion], QmlHighlightKind::QmlKeyword);
781 case DomType::ScriptForEachStatement:
782 m_highlights.addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlKeyword);
783 m_highlights.addHighlight(regions[ForKeywordRegion], QmlHighlightKind::QmlKeyword);
784 m_highlights.addHighlight(regions[InOfTokenRegion], QmlHighlightKind::QmlKeyword);
786 case DomType::ScriptThrowStatement:
787 m_highlights.addHighlight(regions[ThrowKeywordRegion], QmlHighlightKind::QmlKeyword);
789 case DomType::ScriptBreakStatement:
790 m_highlights.addHighlight(regions[BreakKeywordRegion], QmlHighlightKind::QmlKeyword);
792 case DomType::ScriptContinueStatement:
793 m_highlights.addHighlight(regions[ContinueKeywordRegion], QmlHighlightKind::QmlKeyword);
795 case DomType::ScriptIfStatement:
796 m_highlights.addHighlight(regions[IfKeywordRegion], QmlHighlightKind::QmlKeyword);
797 m_highlights.addHighlight(regions[ElseKeywordRegion], QmlHighlightKind::QmlKeyword);
799 case DomType::ScriptLabelledStatement:
800 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::JsLabel);
802 case DomType::ScriptConditionalExpression:
803 m_highlights.addHighlight(regions[QuestionMarkTokenRegion], QmlHighlightKind::Operator);
804 m_highlights.addHighlight(regions[ColonTokenRegion], QmlHighlightKind::Operator);
806 case DomType::ScriptUnaryExpression:
807 case DomType::ScriptPostExpression:
808 m_highlights.addHighlight(regions[OperatorTokenRegion], QmlHighlightKind::Operator);
810 case DomType::ScriptType:
811 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlType);
812 m_highlights.addHighlight(regions[TypeIdentifierRegion], QmlHighlightKind::QmlType);
814 case DomType::ScriptFunctionExpression: {
815 m_highlights.addHighlight(regions[FunctionKeywordRegion], QmlHighlightKind::QmlKeyword);
816 m_highlights.addHighlight(regions[IdentifierRegion], QmlHighlightKind::QmlMethod);
819 case DomType::ScriptYieldExpression:
820 m_highlights.addHighlight(regions[YieldKeywordRegion], QmlHighlightKind::QmlKeyword);
822 case DomType::ScriptThisExpression:
823 m_highlights.addHighlight(regions[ThisKeywordRegion], QmlHighlightKind::QmlKeyword);
825 case DomType::ScriptSuperLiteral:
826 m_highlights.addHighlight(regions[SuperKeywordRegion], QmlHighlightKind::QmlKeyword);
828 case DomType::ScriptNewMemberExpression:
829 case DomType::ScriptNewExpression:
830 m_highlights.addHighlight(regions[NewKeywordRegion], QmlHighlightKind::QmlKeyword);
832 case DomType::ScriptTemplateExpressionPart:
833 m_highlights.addHighlight(regions[DollarLeftBraceTokenRegion], QmlHighlightKind::Operator);
834 visitor(Path(), item.field(Fields::expression),
false);
835 m_highlights.addHighlight(regions[RightBraceRegion], QmlHighlightKind::Operator);
837 case DomType::ScriptTemplateLiteral:
838 m_highlights.addHighlight(regions[LeftBacktickTokenRegion], QmlHighlightKind::String);
839 m_highlights.addHighlight(regions[RightBacktickTokenRegion], QmlHighlightKind::String);
841 case DomType::ScriptTemplateStringPart: {
843 QString code = item.field(Fields::value).value().toString();
844 const auto &locs = HighlightingUtils::sourceLocationsFromMultiLineToken(
845 code, regions[MainRegion]);
846 for (
const auto &loc : locs)
847 m_highlights.addHighlight(loc, QmlHighlightKind::String);
851 qCDebug(semanticTokens) <<
"Script Expressions with kind" << item.internalKind()
852 <<
"not implemented";
857
858
859
860
861
862
863
864
867 const QQmlJS::SourceLocation &locationInDocument)
869 auto lineBreakLength = qsizetype(std::char_traits<
char>::length(
"\n"));
870 const auto lineLengths = [&lineBreakLength](QStringView literal) {
871 std::vector<qsizetype> lineLengths;
872 qsizetype startIndex = 0;
873 qsizetype pos = literal.indexOf(u'\n');
880 if (pos - 1 > 0 && literal[pos - 1] == u'\r') {
882 lineBreakLength = qsizetype(std::char_traits<
char>::length(
"\r\n"));
886 lineLengths.push_back(pos - startIndex);
888 startIndex = pos + lineBreakLength;
889 pos = literal.indexOf(
'\n'_L1, startIndex);
892 if (startIndex < literal.length()) {
893 lineLengths.push_back(literal.length() - startIndex);
898 QList<QQmlJS::SourceLocation> result;
901 QQmlJS::SourceLocation lineLoc = locationInDocument;
902 for (
const auto lineLength : lineLengths(stringLiteral)) {
903 lineLoc.length = lineLength;
904 result.push_back(lineLoc);
907 lineLoc.offset += lineLoc.length + lineBreakLength;
909 lineLoc.startColumn = 1;
917 const auto highlightingTokens = highlights.tokens();
918 constexpr auto tokenEncodingLength = 5;
919 result.reserve(tokenEncodingLength * highlightingTokens.size());
924 std::for_each(highlightingTokens.constBegin(), highlightingTokens.constEnd(), [&](
const auto &token) {
925 Q_ASSERT(token.startLine >= prevLine);
926 if (token.startLine != prevLine)
928 result.emplace_back(token.startLine - prevLine);
929 result.emplace_back(token.startColumn - prevColumn);
930 result.emplace_back(token.length);
931 result.emplace_back(token.tokenType);
932 result.emplace_back(token.tokenModifier);
933 prevLine = token.startLine;
934 prevColumn = token.startColumn;
941
942
943
944
945
946
947
948
949
954 *baseModifier |= (1 <<
int(modifier));
958
959
960
964 int startOffsetItem =
int(loc.offset);
965 int endOffsetItem = startOffsetItem +
int(loc.length);
970
971
972
975 int length = resultID.length();
976 for (
int i = length - 1; i >= 0; --i) {
977 if (resultID[i] ==
'9') {
980 resultID[i] = resultID[i] + 1;
984 resultID.prepend(
'1');
988
989
990
991
992
996 const auto [oldStart, newStart] =
997 std::mismatch(oldData.cbegin(), oldData.cend(), newData.cbegin(), newData.cend());
1001 const auto [r1, r2] = std::mismatch(oldData.crbegin(), std::make_reverse_iterator(oldStart),
1002 newData.crbegin(), std::make_reverse_iterator(newStart));
1003 const auto oldEnd = r1.base();
1004 const auto newEnd = r2.base();
1007 if (oldStart == oldEnd && newStart == newEnd)
1010 SemanticTokensEdit edit;
1011 edit.start =
int(std::distance(newData.cbegin(), newStart));
1012 edit.deleteCount =
int(std::distance(oldStart, oldEnd));
1014 if (newStart >= newData.cbegin() && newEnd <= newData.cend() && newStart < newEnd)
1015 edit.data.emplace(newStart, newEnd);
1017 return { std::move(edit) };
1027 QmlHighlightModifiers modifierKind)
1029 int tokenType = m_mapToProtocol(highlightKind);
1030 int modifierType = fromQmlModifierKindToLspTokenType(modifierKind);
1031 return addHighlightImpl(loc, tokenType, modifierType);
1034void Highlights::addHighlightImpl(
const QQmlJS::SourceLocation &loc,
int tokenType,
int tokenModifier)
1036 if (!loc.isValid()) {
1037 qCDebug(semanticTokens) <<
"Invalid locations: Cannot add highlight to token";
1041 if (loc.length == 0)
1044 if (!m_highlights.contains(loc.offset))
1045 m_highlights.insert(loc.offset, QT_PREPEND_NAMESPACE(Token)(loc, tokenType, tokenModifier));
1049 const std::optional<HighlightsRange> &range,
1050 HighlightingMode mode)
1052 using namespace QQmlJS::Dom;
1058 const std::optional<HighlightsRange> &range,
1059 HighlightingMode mode)
1061 Highlights highlights = visitTokens(item, range, mode);
1062 return HighlightingUtils::encodeSemanticTokens(highlights);
Highlights & highlights()
HighlightingVisitor(const QQmlJS::Dom::DomItem &item, const std::optional< HighlightsRange > &range, HighlightingUtils::HighlightingMode mode=HighlightingUtils::HighlightingMode::Default)
Highlights(HighlightingUtils::HighlightingMode mode=HighlightingUtils::HighlightingMode::Default)
void addHighlight(const QQmlJS::SourceLocation &loc, HighlightingUtils::QmlHighlightKind, HighlightingUtils::QmlHighlightModifiers=HighlightingUtils::QmlHighlightModifier::None)
QList< QQmlJS::SourceLocation > sourceLocationsFromMultiLineToken(QStringView code, const QQmlJS::SourceLocation &tokenLocation)
Returns multiple source locations for a given raw comment.
QList< int > encodeSemanticTokens(Highlights &highlights)
void updateResultID(QByteArray &resultID)
QList< QLspSpecification::SemanticTokensEdit > computeDiff(const QList< int > &, const QList< int > &)
QList< int > collectTokens(const QQmlJS::Dom::DomItem &item, const std::optional< HighlightsRange > &range, HighlightingMode mode=HighlightingMode::Default)
Highlights visitTokens(const QQmlJS::Dom::DomItem &item, const std::optional< HighlightsRange > &range, HighlightingMode mode=HighlightingMode::Default)
bool rangeOverlapsWithSourceLocation(const QQmlJS::SourceLocation &loc, const HighlightsRange &r)
SemanticTokenProtocolTypes
@ QmlExternalObjectProperty
void addModifier(QLspSpecification::SemanticTokenModifiers modifier, int *baseModifier)
@ QmlExternalObjectProperty
static FieldFilter highlightingFilter()
static int mapToProtocolForQtCreator(QmlHighlightKind highlightKind)
static std::optional< QmlHighlightKind > resolveJsGlobalObjectKind(const DomItem &item, const QString &name)
Further resolves the type of a JavaScriptIdentifier A global object can be in the object form or in t...
static int fromQmlModifierKindToLspTokenType(QmlHighlightModifiers highlightModifier)
static int mapToProtocolDefault(QmlHighlightKind highlightKind)