9Q_LOGGING_CATEGORY(QQmlLSCompletionLog,
"qt.languageserver.completions")
11using namespace QLspSpecification;
12using namespace QQmlJS::Dom;
13using namespace Qt::StringLiterals;
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
42CompletionItem
QQmlLSCompletion::makeSnippet(QUtf8StringView qualifier, QUtf8StringView label,
43 QUtf8StringView insertText)
46 if (!qualifier.isEmpty()) {
47 res.label = qualifier.data();
50 res.label += label.data();
51 res.insertTextFormat = InsertTextFormat::Snippet;
52 if (!qualifier.isEmpty()) {
53 res.insertText = qualifier.data();
54 *res.insertText +=
'.';
55 *res.insertText += insertText.data();
57 res.insertText = insertText.data();
59 res.kind = CompletionItemKind::Snippet;
60 res.insertTextMode = InsertTextMode::AdjustIndentation;
64CompletionItem
QQmlLSCompletion::makeSnippet(QUtf8StringView label, QUtf8StringView insertText)
66 return makeSnippet(QByteArray(), label, insertText);
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
90 const QQmlLSCompletionPosition &positionInfo,
91 QQmlJS::SourceLocation right)
const
96 if (!(left.end() <= positionInfo.offset()))
102 return positionInfo.offset() <= right.begin();
106
107
108
110 const QQmlLSCompletionPosition &positionInfo)
const
112 return betweenLocations(left, positionInfo, QQmlJS::SourceLocation{});
116
117
118
120 QQmlJS::SourceLocation right)
const
122 if (!right.isValid())
126 if (ctx.offset() <= right.begin())
132bool QQmlLSCompletion::ctxBeforeStatement(
const QQmlLSCompletionPosition &positionInfo,
133 const DomItem &parentForContext,
134 FileLocationRegion firstRegion)
const
136 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
137 const bool result = beforeLocation(positionInfo, regions[firstRegion]);
142QQmlLSCompletion::suggestBindingCompletion(
const DomItem &itemAtPosition, BackInsertIterator it)
const
144 suggestReachableTypes(itemAtPosition, LocalSymbolsType::AttachedType, CompletionItemKind::Class,
147 const auto scope = [&]() -> QQmlJSScope::ConstPtr {
148 const DomItem owner = ownerOfQualifiedExpression(itemAtPosition);
150 return itemAtPosition.qmlObject().semanticScope();
152 const auto expressionType = QQmlLSUtils::resolveExpressionType(
153 owner, QQmlLSUtils::ResolveActualTypeForFieldMemberExpression);
156 if (!expressionType || expressionType->type == QQmlLSUtils::QualifiedModuleIdentifier)
159 return expressionType->semanticScope;
165 propertyCompletion(scope,
nullptr, it);
166 signalHandlerCompletion(scope,
nullptr, it);
170 const QQmlLSCompletionPosition &positionInfo,
171 BackInsertIterator it)
const
174 const CompletionContextStrings &ctx = positionInfo.cursorPosition;
176 QRegularExpression spaceRe(uR"(\s+)"_s);
177 QList<QStringView> linePieces = ctx.preLine().split(spaceRe, Qt::SkipEmptyParts);
178 qsizetype effectiveLength = linePieces.size()
179 + ((!ctx.preLine().isEmpty() && ctx.preLine().last().isSpace()) ? 1 : 0);
180 if (effectiveLength < 2) {
182 comp.label =
"import";
183 comp.kind = CompletionItemKind::Keyword;
186 if (linePieces.isEmpty() || linePieces.first() != u"import")
188 if (effectiveLength == 2) {
191 }
else if (effectiveLength == 3) {
192 if (linePieces.last() != u"as") {
196 comp.kind = CompletionItemKind::Keyword;
201 DomItem env = file.environment();
202 if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
203 switch (importCompletionType) {
215void QQmlLSCompletion::idsCompletions(
const DomItem &component, BackInsertIterator it)
const
217 qCDebug(QQmlLSCompletionLog) <<
"adding ids completions";
218 for (
const QString &k : component.field(Fields::ids).keys()) {
220 comp.label = k.toUtf8();
221 comp.kind = CompletionItemKind::Value;
226static bool testScopeSymbol(
const QQmlJSScope::ConstPtr &scope, LocalSymbolsTypes options,
227 CompletionItemKind kind)
229 const bool currentIsSingleton = scope->isSingleton();
230 const bool currentIsAttached = !scope->attachedType().isNull();
231 if ((options & LocalSymbolsType::Singleton) && currentIsSingleton) {
234 if ((options & LocalSymbolsType::AttachedType) && currentIsAttached) {
237 const bool isObjectType = scope->isReferenceType();
238 if (options & LocalSymbolsType::ObjectType && !currentIsSingleton && isObjectType) {
239 return kind != CompletionItemKind::Constructor || scope->isCreatable();
241 if (options & LocalSymbolsType::ValueType && !currentIsSingleton && !isObjectType) {
248
249
250
251void QQmlLSCompletion::suggestReachableTypes(
const DomItem &el, LocalSymbolsTypes options,
252 CompletionItemKind kind, BackInsertIterator it)
const
254 auto file = el.containingFile().as<QmlFile>();
257 auto resolver = file->typeResolver();
261 const QString requiredQualifiers = QQmlLSUtils::qualifiersFrom(el);
262 const auto keyValueRange = resolver->importedTypes().asKeyValueRange();
263 for (
const auto &type : keyValueRange) {
265 const bool isMarkerType = type.first.contains(u"$internal$.")
266 || type.first.contains(u"$anonymous$.") || type.first.contains(u"$module$.");
267 if (isMarkerType || !type.first.startsWith(requiredQualifiers))
270 auto &scope = type.second.scope;
274 if (!testScopeSymbol(scope, options, kind))
277 CompletionItem completion;
278 completion.label = QStringView(type.first).sliced(requiredQualifiers.size()).toUtf8();
279 completion.kind = kind;
284void QQmlLSCompletion::jsIdentifierCompletion(
const QQmlJSScope::ConstPtr &scope,
285 QDuplicateTracker<QString> *usedNames,
286 BackInsertIterator it)
const
288 for (
const auto &[name, jsIdentifier] : scope->ownJSIdentifiers().asKeyValueRange()) {
289 CompletionItem completion;
290 if (usedNames && usedNames->hasSeen(name)) {
293 completion.label = name.toUtf8();
294 completion.kind = CompletionItemKind::Variable;
295 QString detail = u"has type "_s;
296 if (jsIdentifier.typeName) {
297 if (jsIdentifier.isConst) {
298 detail.append(u"const ");
300 detail.append(*jsIdentifier.typeName);
302 detail.append(jsIdentifier.isConst ? u"const"_s : u"var"_s);
304 completion.detail = detail.toUtf8();
310 QDuplicateTracker<QString> *usedNames,
311 BackInsertIterator it)
const
314 for (
const auto &[name, method] : scope->methods().asKeyValueRange()) {
315 if (method.access() != QQmlJSMetaMethod::Public)
317 if (usedNames && usedNames->hasSeen(name)) {
320 CompletionItem completion;
321 completion.label = name.toUtf8();
322 completion.kind = CompletionItemKind::Method;
329void QQmlLSCompletion::propertyCompletion(
const QQmlJSScope::ConstPtr &scope,
330 QDuplicateTracker<QString> *usedNames,
331 BackInsertIterator it)
const
333 for (
const auto &[name, property] : scope->properties().asKeyValueRange()) {
334 if (usedNames && usedNames->hasSeen(name)) {
337 CompletionItem completion;
338 completion.label = name.toUtf8();
339 completion.kind = CompletionItemKind::Property;
340 QString detail{ u"has type "_s };
341 if (!property.isWritable())
342 detail.append(u"readonly "_s);
343 detail.append(property.typeName().isEmpty() ? u"var"_s : property.typeName());
344 completion.detail = detail.toUtf8();
349void QQmlLSCompletion::enumerationCompletion(
const QQmlJSScope::ConstPtr &scope,
350 QDuplicateTracker<QString> *usedNames,
351 BackInsertIterator it)
const
353 for (
const QQmlJSMetaEnum &enumerator : scope->enumerations()) {
354 if (usedNames && usedNames->hasSeen(enumerator.name())) {
357 CompletionItem completion;
358 completion.label = enumerator.name().toUtf8();
359 completion.kind = CompletionItemKind::Enum;
364void QQmlLSCompletion::enumerationValueCompletionHelper(
const QStringList &enumeratorKeys,
365 BackInsertIterator it)
const
367 for (
const QString &enumeratorKey : enumeratorKeys) {
368 CompletionItem completion;
369 completion.label = enumeratorKey.toUtf8();
370 completion.kind = CompletionItemKind::EnumMember;
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
395void QQmlLSCompletion::enumerationValueCompletion(
const QQmlJSScope::ConstPtr &scope,
396 const QString &enumeratorName,
397 BackInsertIterator result)
const
399 auto enumerator = scope->enumeration(enumeratorName);
400 if (enumerator.isValid()) {
401 enumerationValueCompletionHelper(enumerator.keys(), result);
405 for (
const QQmlJSMetaEnum &enumerator : scope->enumerations()) {
406 enumerationValueCompletionHelper(enumerator.keys(), result);
411
412
413
414
415
416
417
418
419
420
421
422
426 for (QQmlJSScope::ConstPtr current = scope; current; current = current->parentScope()) {
428 if (current->scopeType() == QQmlSA::ScopeType::QMLScope)
434
435
436
437
438
439
440
441
442
444 const QQmlJSScope::ConstPtr &scope,
const QString &enumName,
445 QDuplicateTracker<QString> &usedNames, BackInsertIterator result)
const
447 enumerationValueCompletion(scope, enumName, result);
450 if (
auto enumerator = scope->enumeration(enumName); !enumerator.isValid()) {
451 enumerationCompletion(scope, &usedNames, result);
456
457
458
459
460
461
462
463
464
465DomItem
QQmlLSCompletion::ownerOfQualifiedExpression(
const DomItem &qualifiedExpression)
const
470 const bool askForCompletionOnDot = QQmlLSUtils::isFieldMemberExpression(qualifiedExpression);
471 const bool hasQualifier =
472 QQmlLSUtils::isFieldMemberAccess(qualifiedExpression) || askForCompletionOnDot;
477 const DomItem owner =
478 (askForCompletionOnDot ? qualifiedExpression : qualifiedExpression.directParent())
479 .field(Fields::left);
484
485
486
487
488
489
490
491
492void QQmlLSCompletion::suggestJSExpressionCompletion(
const DomItem &scriptIdentifier,
493 BackInsertIterator result)
const
495 QDuplicateTracker<QString> usedNames;
496 QQmlJSScope::ConstPtr nearestScope;
498 const DomItem owner = ownerOfQualifiedExpression(scriptIdentifier);
501 for (QUtf8StringView view : std::array<QUtf8StringView, 3>{
"null",
"false",
"true" }) {
502 CompletionItem completion;
503 completion.label = view.data();
504 completion.kind = CompletionItemKind::Value;
507 idsCompletions(scriptIdentifier.component(), result);
508 suggestReachableTypes(scriptIdentifier,
509 LocalSymbolsType::Singleton | LocalSymbolsType::AttachedType,
510 CompletionItemKind::Class, result);
512 auto scope = scriptIdentifier.nearestSemanticScope();
515 nearestScope = scope;
517 enumerationCompletion(nearestScope, &usedNames, result);
519 auto ownerExpressionType = QQmlLSUtils::resolveExpressionType(
520 owner, QQmlLSUtils::ResolveActualTypeForFieldMemberExpression);
521 if (!ownerExpressionType || !ownerExpressionType->semanticScope)
523 nearestScope = ownerExpressionType->semanticScope;
525 switch (ownerExpressionType->type) {
526 case QQmlLSUtils::EnumeratorValueIdentifier:
528 case QQmlLSUtils::EnumeratorIdentifier:
529 suggestEnumerationsAndEnumerationValues(nearestScope, *ownerExpressionType->name,
532 case QQmlLSUtils::QmlComponentIdentifier:
535 if (QQmlJSScope::ConstPtr attachedType =
536 ownerExpressionType->semanticScope->attachedType()) {
537 methodCompletion(attachedType, &usedNames, result);
538 propertyCompletion(attachedType, &usedNames, result);
539 suggestEnumerationsAndEnumerationValues(
540 attachedType, *ownerExpressionType->name, usedNames, result);
543 case QQmlLSUtils::SingletonIdentifier:
544 if (ownerExpressionType->name)
545 suggestEnumerationsAndEnumerationValues(nearestScope, *ownerExpressionType->name,
553 Q_ASSERT(nearestScope);
555 methodCompletion(nearestScope, &usedNames, result);
556 propertyCompletion(nearestScope, &usedNames, result);
560 collectFromAllJavaScriptParents(
561 [
this, &usedNames, result](
const QQmlJSScope::ConstPtr &scope) {
562 jsIdentifierCompletion(scope, &usedNames, result);
565 collectFromAllJavaScriptParents(
566 [
this, &usedNames, result](
const QQmlJSScope::ConstPtr &scope) {
567 methodCompletion(scope, &usedNames, result);
570 collectFromAllJavaScriptParents(
571 [
this, &usedNames, result](
const QQmlJSScope::ConstPtr &scope) {
572 propertyCompletion(scope, &usedNames, result);
576 auto file = scriptIdentifier.containingFile().as<QmlFile>();
579 auto resolver = file->typeResolver();
583 const auto globals = resolver->jsGlobalObject();
584 methodCompletion(globals, &usedNames, result);
585 propertyCompletion(globals, &usedNames, result);
591 for (
const QString &name : names) {
592 if (
auto property = current->property(name); property.isValid()) {
593 if (
auto propertyType = property.type().get()) {
594 current = propertyType;
604 const QQmlLSCompletionPosition &positionInfo)
606 auto fileLocations = FileLocations::treeOf(parentForContext)->info().fullRegion;
607 return positionInfo.offset() <= fileLocations.begin();
611 const QQmlLSCompletionPosition &positionInfo)
613 auto location = FileLocations::treeOf(currentItem)->info();
614 auto region = location.regions.constFind(ColonTokenRegion);
616 if (region == location.regions.constEnd())
619 if (region.value().isValid() && region.value().begin() < positionInfo.offset()) {
626
627
628
629
630
631
632
633
634
635
636static const QMap<QString, QList<QString>> valuesForPragmas{
637 { u"ComponentBehavior"_s, { u"Unbound"_s, u"Bound"_s } },
638 { u"NativeMethodBehavior"_s, { u"AcceptThisObject"_s, u"RejectThisObject"_s } },
639 { u"ListPropertyAssignBehavior"_s, { u"Append"_s, u"Replace"_s, u"ReplaceIfNotDefault"_s } },
640 { u"Singleton"_s, {} },
641 { u"ValueTypeBehavior"_s, { u"Addressable"_s, u"Inaddressable"_s } },
644void QQmlLSCompletion::insidePragmaCompletion(QQmlJS::Dom::DomItem currentItem,
645 const QQmlLSCompletionPosition &positionInfo,
646 BackInsertIterator result)
const
648 if (cursorAfterColon(currentItem, positionInfo)) {
649 const QString name = currentItem.field(Fields::name).value().toString();
650 auto values = valuesForPragmas.constFind(name);
651 if (values == valuesForPragmas.constEnd())
654 for (
const auto &value : *values) {
656 comp.label = value.toUtf8();
657 comp.kind = CompletionItemKind::Value;
663 for (
const auto &pragma : valuesForPragmas.asKeyValueRange()) {
665 comp.label = pragma.first.toUtf8();
666 if (!pragma.second.isEmpty()) {
667 comp.insertText = QString(pragma.first).append(u": ").toUtf8();
669 comp.kind = CompletionItemKind::Value;
674void QQmlLSCompletion::insideQmlObjectCompletion(
const DomItem &parentForContext,
675 const QQmlLSCompletionPosition &positionInfo,
676 BackInsertIterator result)
const
679 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
681 const QQmlJS::SourceLocation leftBrace = regions[LeftBraceRegion];
682 const QQmlJS::SourceLocation rightBrace = regions[RightBraceRegion];
684 if (beforeLocation(positionInfo, leftBrace)) {
685 LocalSymbolsTypes options;
686 options.setFlag(LocalSymbolsType::ObjectType);
687 suggestReachableTypes(positionInfo.itemAtPosition, options, CompletionItemKind::Constructor,
689 if (parentForContext.directParent().internalKind() == DomType::Binding)
690 suggestSnippetsForRightHandSideOfBinding(positionInfo.itemAtPosition, result);
692 suggestSnippetsForLeftHandSideOfBinding(positionInfo.itemAtPosition, result);
694 if (QQmlLSUtils::isFieldMemberExpression(positionInfo.itemAtPosition)) {
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
721 if (betweenLocations(leftBrace, positionInfo, rightBrace)) {
725 constexpr static std::array completions{
""_L1,
733 "default virtual "_L1,
734 "default override "_L1,
735 "default required "_L1,
736 "final required "_L1,
737 "final readonly "_L1,
738 "virtual required "_L1,
739 "virtual readonly "_L1,
740 "override required "_L1,
741 "override readonly "_L1,
742 "default final required "_L1,
743 "default virtual required "_L1,
744 "default override required "_L1 };
745 for (QLatin1StringView completion : completions) {
750 if (!completion.contains(QLatin1StringView(
"readonly"))) {
751 result = makeSnippet(
752 QByteArray(completion.data()).append(
"property type name;"),
753 QByteArray(completion.data()).append(
"property ${1:type} ${0:name};"));
756 if (!completion.contains(QLatin1StringView(
"required"))) {
757 result = makeSnippet(
758 QByteArray(completion.data()).append(
"property type name: value;"),
759 QByteArray(completion.data())
760 .append(
"property ${1:type} ${2:name}: ${0:value};"));
765 result = makeSnippet(
"signal name(arg1:type1, ...)",
"signal ${1:name}($0)");
768 result = makeSnippet(
"signal name;",
"signal ${0:name};");
771 result = makeSnippet(
"required name;",
"required ${0:name};");
774 result = makeSnippet(
"function name(args...): returnType { statements...}",
775 "function ${1:name}($2): ${3:returnType} {\n\t$0\n}");
778 result = makeSnippet(
"enum name { Values...}",
"enum ${1:name} {\n\t${0:values}\n}");
781 result = makeSnippet(
"component Name: BaseType { ... }",
782 "component ${1:name}: ${2:baseType} {\n\t$0\n}");
784 suggestBindingCompletion(positionInfo.itemAtPosition, result);
787 const DomItem containingFile = parentForContext.containingFile();
788 suggestReachableTypes(containingFile, LocalSymbolsType::ObjectType,
789 CompletionItemKind::Constructor, result);
790 suggestSnippetsForLeftHandSideOfBinding(positionInfo.itemAtPosition, result);
797 const DomItem ¤tItem,
const QQmlLSCompletionPosition &positionInfo,
798 BackInsertIterator result)
const
800 auto info = FileLocations::treeOf(currentItem)->info();
801 const QQmlJS::SourceLocation propertyKeyword = info.regions[PropertyKeywordRegion];
804 if (positionInfo.offset() < propertyKeyword.end()) {
805 auto addCompletionKeyword = [&result](QUtf8StringView view) {
807 item.label = view.data();
808 item.kind = CompletionItemKind::Keyword;
812 const auto alreadyTyped = [&info,
813 &positionInfo](
const FileLocationRegion &keywordRegion) ->
bool {
814 const auto &keywordSLoc = info.regions[keywordRegion];
815 return keywordSLoc.isValid() && keywordSLoc.begin() < positionInfo.offset();
818 const bool alreadyTypedReadonlyOrRequired =
819 alreadyTyped(ReadonlyKeywordRegion) || alreadyTyped(RequiredKeywordRegion);
820 if (!alreadyTypedReadonlyOrRequired) {
825 addCompletionKeyword(u8"readonly");
826 addCompletionKeyword(u8"required");
829 if (!alreadyTyped(DefaultKeywordRegion)) {
830 addCompletionKeyword(u8"default");
833 const bool alreadyTypedVirtualOrOverrideOrFinal = alreadyTyped(VirtualKeywordRegion)
834 || alreadyTyped(OverrideKeywordRegion) || alreadyTyped(FinalKeywordRegion);
835 if (!alreadyTypedVirtualOrOverrideOrFinal) {
840 addCompletionKeyword(u8"final");
841 addCompletionKeyword(u8"virtual");
842 addCompletionKeyword(u8"override");
845 addCompletionKeyword(u8"property");
850 const QQmlJS::SourceLocation propertyIdentifier = info.regions[IdentifierRegion];
851 if (propertyKeyword.end() <= positionInfo.offset()
852 && positionInfo.offset() < propertyIdentifier.begin()) {
853 suggestReachableTypes(currentItem,
854 LocalSymbolsType::ObjectType | LocalSymbolsType::ValueType,
855 CompletionItemKind::Class, result);
862 const QQmlLSCompletionPosition &positionInfo,
863 BackInsertIterator result)
const
865 const DomItem containingBinding = currentItem.filterUp(
866 [](DomType type,
const QQmlJS::Dom::DomItem &) {
return type == DomType::Binding; },
867 FilterUpOptions::ReturnOuter);
870 if (cursorAfterColon(containingBinding, positionInfo)) {
871 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
873 if (
auto type = QQmlLSUtils::resolveExpressionType(currentItem,
874 QQmlLSUtils::ResolveOwnerType)) {
875 const QStringList names = currentItem.field(Fields::name).toString().split(u'.');
876 const QQmlJSScope *current = resolve(type->semanticScope.get(), names);
878 if (!current || current->accessSemantics() == QQmlSA::AccessSemantics::Reference) {
879 LocalSymbolsTypes options;
880 options.setFlag(LocalSymbolsType::ObjectType);
881 suggestReachableTypes(positionInfo.itemAtPosition, options,
882 CompletionItemKind::Constructor, result);
883 suggestSnippetsForRightHandSideOfBinding(positionInfo.itemAtPosition, result);
890 if (cursorInFrontOfItem(containingBinding, positionInfo)) {
891 insideQmlObjectCompletion(currentItem.containingObject(), positionInfo, result);
895 const DomItem containingObject = currentItem.qmlObject();
897 suggestBindingCompletion(positionInfo.itemAtPosition, result);
900 suggestReachableTypes(positionInfo.itemAtPosition, LocalSymbolsType::ObjectType,
901 CompletionItemKind::Constructor, result);
902 suggestSnippetsForLeftHandSideOfBinding(positionInfo.itemAtPosition, result);
906 const QQmlLSCompletionPosition &positionInfo,
907 BackInsertIterator result)
const
909 const DomItem containingFile = currentItem.containingFile();
910 insideImportCompletionHelper(containingFile, positionInfo, result);
913 if (cursorInFrontOfItem(currentItem, positionInfo)) {
914 suggestReachableTypes(containingFile, LocalSymbolsType::ObjectType,
915 CompletionItemKind::Constructor, result);
920 const QQmlLSCompletionPosition &positionInfo,
921 BackInsertIterator result)
const
923 const DomItem containingFile = currentItem.containingFile();
926 if (positionInfo.cursorPosition.atLineStart()) {
927 if (positionInfo.cursorPosition.base().isEmpty()) {
928 for (
const QStringView &s : std::array<QStringView, 2>({ u"pragma", u"import" })) {
930 comp.label = s.toUtf8();
931 comp.kind = CompletionItemKind::Keyword;
937 suggestReachableTypes(containingFile, LocalSymbolsType::ObjectType,
938 CompletionItemKind::Constructor, result);
942
943
944
949 for (
auto view : std::array<QUtf8StringView, 3>{
"let",
"var",
"const" }) {
950 auto snippet = makeSnippet(QByteArray(view.data()).append(
" variable = value"),
951 QByteArray(view.data()).append(
" ${1:variable} = $0"));
952 if (option == AppendSemicolon) {
953 snippet.insertText->append(
";");
954 snippet.label.append(
";");
961
962
963
964void QQmlLSCompletion::suggestCaseAndDefaultStatementCompletion(BackInsertIterator result)
const
967 result = makeSnippet(
"case value: statements...",
"case ${1:value}:\n\t$0");
969 result = makeSnippet(
"case value: { statements... }",
"case ${1:value}: {\n\t$0\n}");
972 result = makeSnippet(
"default: statements...",
"default:\n\t$0");
974 result = makeSnippet(
"default: { statements... }",
"default: {\n\t$0\n}");
978
979
980
981
982
983
984
985
986void QQmlLSCompletion::suggestContinueAndBreakStatementIfNeeded(
const DomItem &itemAtPosition,
987 BackInsertIterator result)
const
989 bool alreadyInLabel =
false;
990 bool alreadyInSwitch =
false;
991 for (DomItem current = itemAtPosition; current; current = current.directParent()) {
992 switch (current.internalKind()) {
993 case DomType::ScriptExpression:
997 case DomType::ScriptForStatement:
998 case DomType::ScriptForEachStatement:
999 case DomType::ScriptWhileStatement:
1000 case DomType::ScriptDoWhileStatement: {
1001 CompletionItem continueKeyword;
1002 continueKeyword.label =
"continue";
1003 continueKeyword.kind = CompletionItemKind::Keyword;
1004 result = continueKeyword;
1007 if (!alreadyInSwitch && !alreadyInLabel) {
1008 CompletionItem breakKeyword;
1009 breakKeyword.label =
"break";
1010 breakKeyword.kind = CompletionItemKind::Keyword;
1011 result = breakKeyword;
1016 case DomType::ScriptSwitchStatement: {
1018 if (alreadyInSwitch || alreadyInLabel)
1020 alreadyInSwitch =
true;
1022 CompletionItem breakKeyword;
1023 breakKeyword.label =
"break";
1024 breakKeyword.kind = CompletionItemKind::Keyword;
1025 result = breakKeyword;
1028 case DomType::ScriptLabelledStatement: {
1030 if (alreadyInSwitch || alreadyInLabel)
1032 alreadyInLabel =
true;
1034 CompletionItem breakKeyword;
1035 breakKeyword.label =
"break";
1036 breakKeyword.kind = CompletionItemKind::Keyword;
1037 result = breakKeyword;
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062void QQmlLSCompletion::suggestJSStatementCompletion(
const DomItem &itemAtPosition,
1063 BackInsertIterator result)
const
1065 suggestJSExpressionCompletion(itemAtPosition, result);
1067 if (QQmlLSUtils::isFieldMemberAccess(itemAtPosition)
1068 || QQmlLSUtils::isFieldMemberExpression(itemAtPosition))
1072 suggestVariableDeclarationStatementCompletion(result);
1074 result = makeSnippet(
"{ statements... }",
"{\n\t$0\n}");
1077 result = makeSnippet(
"if (condition) { statements }",
"if ($1) {\n\t$0\n}");
1080 result = makeSnippet(
"do { statements } while (condition);",
"do {\n\t$1\n} while ($0);");
1083 result = makeSnippet(
"while (condition) { statements...}",
"while ($1) {\n\t$0\n}");
1086 result = makeSnippet(
"for (initializer; condition; increment) { statements... }",
1087 "for ($1;$2;$3) {\n\t$0\n}");
1090 result = makeSnippet(
"for (property in object) { statements... }",
"for ($1 in $2) {\n\t$0\n}");
1093 result = makeSnippet(
"for (element of array) { statements... }",
"for ($1 of $2) {\n\t$0\n}");
1096 result = makeSnippet(
"try { statements... } catch(error) { statements... }",
1097 "try {\n\t$1\n} catch($2) {\n\t$0\n}");
1100 result = makeSnippet(
"try { statements... } finally { statements... }",
1101 "try {\n\t$1\n} finally {\n\t$0\n}");
1104 result = makeSnippet(
1105 "try { statements... } catch(error) { statements... } finally { statements... }",
1106 "try {\n\t$1\n} catch($2) {\n\t$3\n} finally {\n\t$0\n}");
1109 for (
const QByteArray &view : {
"return"_ba,
"throw"_ba }) {
1110 CompletionItem item;
1112 item.kind = CompletionItemKind::Keyword;
1130 const DomType currentKind = itemAtPosition.internalKind();
1131 const DomType parentKind = itemAtPosition.directParent().internalKind();
1132 if (currentKind == DomType::ScriptCaseBlock || currentKind == DomType::ScriptCaseClause
1133 || currentKind == DomType::ScriptDefaultClause
1134 || (currentKind == DomType::List
1135 && (parentKind == DomType::ScriptCaseClause
1136 || parentKind == DomType::ScriptDefaultClause))) {
1137 suggestCaseAndDefaultStatementCompletion(result);
1139 suggestContinueAndBreakStatementIfNeeded(itemAtPosition, result);
1142void QQmlLSCompletion::insideForStatementCompletion(
const DomItem &parentForContext,
1143 const QQmlLSCompletionPosition &positionInfo,
1144 BackInsertIterator result)
const
1146 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1148 const QQmlJS::SourceLocation leftParenthesis = regions[LeftParenthesisRegion];
1149 const QQmlJS::SourceLocation firstSemicolon = regions[FirstSemicolonTokenRegion];
1150 const QQmlJS::SourceLocation secondSemicolon = regions[SecondSemicolonRegion];
1151 const QQmlJS::SourceLocation rightParenthesis = regions[RightParenthesisRegion];
1153 if (betweenLocations(leftParenthesis, positionInfo, firstSemicolon)) {
1154 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1155 suggestVariableDeclarationStatementCompletion(result,
1156 AppendOption::AppendNothing);
1159 if (betweenLocations(firstSemicolon, positionInfo, secondSemicolon)
1160 || betweenLocations(secondSemicolon, positionInfo, rightParenthesis)) {
1161 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1165 if (afterLocation(rightParenthesis, positionInfo)) {
1166 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1171void QQmlLSCompletion::insideScriptLiteralCompletion(
const DomItem ¤tItem,
1172 const QQmlLSCompletionPosition &positionInfo,
1173 BackInsertIterator result)
const
1175 Q_UNUSED(currentItem);
1176 if (positionInfo.cursorPosition.base().isEmpty()) {
1177 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1183 const QQmlLSCompletionPosition &positionInfo,
1184 BackInsertIterator result)
const
1186 const auto regions = FileLocations::treeOf(currentItem)->info().regions;
1187 const QQmlJS::SourceLocation leftParenthesis = regions[LeftParenthesisRegion];
1188 const QQmlJS::SourceLocation rightParenthesis = regions[RightParenthesisRegion];
1189 if (beforeLocation(positionInfo, leftParenthesis)) {
1190 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1193 if (betweenLocations(leftParenthesis, positionInfo, rightParenthesis)) {
1194 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1200 const QQmlLSCompletionPosition &positionInfo,
1201 BackInsertIterator result)
const
1203 const auto regions = FileLocations::treeOf(currentItem)->info().regions;
1204 const QQmlJS::SourceLocation leftParenthesis = regions[LeftParenthesisRegion];
1205 const QQmlJS::SourceLocation rightParenthesis = regions[RightParenthesisRegion];
1206 const QQmlJS::SourceLocation elseKeyword = regions[ElseKeywordRegion];
1208 if (betweenLocations(leftParenthesis, positionInfo, rightParenthesis)) {
1209 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1212 if (betweenLocations(rightParenthesis, positionInfo, elseKeyword)) {
1213 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1216 if (afterLocation(elseKeyword, positionInfo)) {
1217 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1223 const QQmlLSCompletionPosition &positionInfo,
1224 BackInsertIterator result)
const
1226 const auto regions = FileLocations::treeOf(currentItem)->info().regions;
1227 const QQmlJS::SourceLocation returnKeyword = regions[ReturnKeywordRegion];
1229 if (afterLocation(returnKeyword, positionInfo)) {
1230 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1236 const QQmlLSCompletionPosition &positionInfo,
1237 BackInsertIterator result)
const
1239 const auto regions = FileLocations::treeOf(currentItem)->info().regions;
1240 const QQmlJS::SourceLocation leftParenthesis = regions[LeftParenthesisRegion];
1241 const QQmlJS::SourceLocation rightParenthesis = regions[RightParenthesisRegion];
1243 if (betweenLocations(leftParenthesis, positionInfo, rightParenthesis)) {
1244 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1247 if (afterLocation(rightParenthesis, positionInfo)) {
1248 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1253void QQmlLSCompletion::insideDoWhileStatement(
const DomItem &parentForContext,
1254 const QQmlLSCompletionPosition &positionInfo,
1255 BackInsertIterator result)
const
1257 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1258 const QQmlJS::SourceLocation doKeyword = regions[DoKeywordRegion];
1259 const QQmlJS::SourceLocation whileKeyword = regions[WhileKeywordRegion];
1260 const QQmlJS::SourceLocation leftParenthesis = regions[LeftParenthesisRegion];
1261 const QQmlJS::SourceLocation rightParenthesis = regions[RightParenthesisRegion];
1263 if (betweenLocations(doKeyword, positionInfo, whileKeyword)) {
1264 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1267 if (betweenLocations(leftParenthesis, positionInfo, rightParenthesis)) {
1268 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1273void QQmlLSCompletion::insideForEachStatement(
const DomItem &parentForContext,
1274 const QQmlLSCompletionPosition &positionInfo,
1275 BackInsertIterator result)
const
1277 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1279 const QQmlJS::SourceLocation inOf = regions[InOfTokenRegion];
1280 const QQmlJS::SourceLocation leftParenthesis = regions[LeftParenthesisRegion];
1281 const QQmlJS::SourceLocation rightParenthesis = regions[RightParenthesisRegion];
1283 if (betweenLocations(leftParenthesis, positionInfo, inOf)) {
1284 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1285 suggestVariableDeclarationStatementCompletion(result);
1288 if (betweenLocations(inOf, positionInfo, rightParenthesis)) {
1289 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1293 if (afterLocation(rightParenthesis, positionInfo)) {
1294 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1299void QQmlLSCompletion::insideSwitchStatement(
const DomItem &parentForContext,
1300 const QQmlLSCompletionPosition positionInfo,
1301 BackInsertIterator result)
const
1303 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1305 const QQmlJS::SourceLocation leftParenthesis = regions[LeftParenthesisRegion];
1306 const QQmlJS::SourceLocation rightParenthesis = regions[RightParenthesisRegion];
1308 if (betweenLocations(leftParenthesis, positionInfo, rightParenthesis)) {
1309 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1315 const QQmlLSCompletionPosition &positionInfo,
1316 BackInsertIterator result)
const
1318 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1320 const QQmlJS::SourceLocation caseKeyword = regions[CaseKeywordRegion];
1321 const QQmlJS::SourceLocation colonToken = regions[ColonTokenRegion];
1323 if (betweenLocations(caseKeyword, positionInfo, colonToken)) {
1324 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1327 if (afterLocation(colonToken, positionInfo)) {
1328 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1335
1336
1337
1338bool QQmlLSCompletion::isCaseOrDefaultBeforeCtx(
const DomItem ¤tClause,
1339 const QQmlLSCompletionPosition &positionInfo,
1340 FileLocationRegion keywordRegion)
const
1342 Q_ASSERT(keywordRegion == QQmlJS::Dom::CaseKeywordRegion
1343 || keywordRegion == QQmlJS::Dom::DefaultKeywordRegion);
1348 const auto token = FileLocations::treeOf(currentClause)->info().regions[keywordRegion];
1349 if (afterLocation(token, positionInfo))
1356
1357
1358
1359
1360
1361
1362
1365 const QQmlLSCompletionPosition &positionInfo)
const
1367 const DomItem caseClauses = parentForContext.field(Fields::caseClauses);
1368 for (
int i = 0; i < caseClauses.indexes(); ++i) {
1369 const DomItem currentClause = caseClauses.index(i);
1370 if (isCaseOrDefaultBeforeCtx(currentClause, positionInfo, QQmlJS::Dom::CaseKeywordRegion)) {
1371 return currentClause;
1375 const DomItem defaultClause = parentForContext.field(Fields::defaultClause);
1376 if (isCaseOrDefaultBeforeCtx(defaultClause, positionInfo, QQmlJS::Dom::DefaultKeywordRegion))
1377 return parentForContext.field(Fields::defaultClause);
1379 const DomItem moreCaseClauses = parentForContext.field(Fields::moreCaseClauses);
1380 for (
int i = 0; i < moreCaseClauses.indexes(); ++i) {
1381 const DomItem currentClause = moreCaseClauses.index(i);
1382 if (isCaseOrDefaultBeforeCtx(currentClause, positionInfo, QQmlJS::Dom::CaseKeywordRegion)) {
1383 return currentClause;
1391 const QQmlLSCompletionPosition &positionInfo,
1392 BackInsertIterator result)
const
1394 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1396 const QQmlJS::SourceLocation leftBrace = regions[LeftBraceRegion];
1397 const QQmlJS::SourceLocation rightBrace = regions[RightBraceRegion];
1399 if (!betweenLocations(leftBrace, positionInfo, rightBrace))
1404 if (
const auto previousCase = previousCaseOfCaseBlock(parentForContext, positionInfo)) {
1405 suggestJSStatementCompletion(previousCase, result);
1410 suggestCaseAndDefaultStatementCompletion(result);
1414 const QQmlLSCompletionPosition &positionInfo,
1415 BackInsertIterator result)
const
1417 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1419 const QQmlJS::SourceLocation colonToken = regions[ColonTokenRegion];
1421 if (afterLocation(colonToken, positionInfo)) {
1422 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1428 const DomItem &parentForContext,
const QQmlLSCompletionPosition &positionInfo,
1429 BackInsertIterator result)
const
1431 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1433 const QQmlJS::SourceLocation operatorLocation = regions[OperatorTokenRegion];
1435 if (beforeLocation(positionInfo, operatorLocation)) {
1436 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1439 if (afterLocation(operatorLocation, positionInfo)) {
1440 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1486 const QQmlLSCompletionPosition &positionInfo,
1487 BackInsertIterator result)
const
1489 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1491 const QQmlJS::SourceLocation equal = regions[EqualTokenRegion];
1493 if (!afterLocation(equal, positionInfo))
1497 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1501
1502
1503
1504void QQmlLSCompletion::insideVariableDeclarationEntry(
const DomItem &parentForContext,
1505 const QQmlLSCompletionPosition &positionInfo,
1506 BackInsertIterator result)
const
1508 insideScriptPattern(parentForContext, positionInfo, result);
1511void QQmlLSCompletion::insideThrowStatement(
const DomItem &parentForContext,
1512 const QQmlLSCompletionPosition &positionInfo,
1513 BackInsertIterator result)
const
1515 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1517 const QQmlJS::SourceLocation throwKeyword = regions[ThrowKeywordRegion];
1519 if (afterLocation(throwKeyword, positionInfo)) {
1520 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1525void QQmlLSCompletion::insideLabelledStatement(
const DomItem &parentForContext,
1526 const QQmlLSCompletionPosition &positionInfo,
1527 BackInsertIterator result)
const
1529 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1531 const QQmlJS::SourceLocation colon = regions[ColonTokenRegion];
1533 if (afterLocation(colon, positionInfo)) {
1534 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1545
1546
1547
1548static void collectLabels(
const DomItem &context, QQmlLSCompletion::BackInsertIterator result)
1550 for (DomItem current = context; current; current = current.directParent()) {
1551 if (current.internalKind() == DomType::ScriptLabelledStatement) {
1552 const QString label = current.field(Fields::label).value().toString();
1553 if (label.isEmpty())
1555 CompletionItem item;
1556 item.label = label.toUtf8();
1557 item.kind = CompletionItemKind::Value;
1560 }
else if (current.internalKind() == DomType::ScriptExpression) {
1568void QQmlLSCompletion::insideContinueStatement(
const DomItem &parentForContext,
1569 const QQmlLSCompletionPosition &positionInfo,
1570 BackInsertIterator result)
const
1572 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1574 const QQmlJS::SourceLocation continueKeyword = regions[ContinueKeywordRegion];
1576 if (afterLocation(continueKeyword, positionInfo)) {
1577 collectLabels(parentForContext, result);
1582void QQmlLSCompletion::insideBreakStatement(
const DomItem &parentForContext,
1583 const QQmlLSCompletionPosition &positionInfo,
1584 BackInsertIterator result)
const
1586 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1588 const QQmlJS::SourceLocation breakKeyword = regions[BreakKeywordRegion];
1590 if (afterLocation(breakKeyword, positionInfo)) {
1591 collectLabels(parentForContext, result);
1596void QQmlLSCompletion::insideConditionalExpression(
const DomItem &parentForContext,
1597 const QQmlLSCompletionPosition &positionInfo,
1598 BackInsertIterator result)
const
1600 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1602 const QQmlJS::SourceLocation questionMark = regions[QuestionMarkTokenRegion];
1603 const QQmlJS::SourceLocation colon = regions[ColonTokenRegion];
1605 if (beforeLocation(positionInfo, questionMark)) {
1606 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1609 if (betweenLocations(questionMark, positionInfo, colon)) {
1610 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1613 if (afterLocation(colon, positionInfo)) {
1614 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1619void QQmlLSCompletion::insideUnaryExpression(
const DomItem &parentForContext,
1620 const QQmlLSCompletionPosition &positionInfo,
1621 BackInsertIterator result)
const
1623 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1625 const QQmlJS::SourceLocation operatorToken = regions[OperatorTokenRegion];
1627 if (afterLocation(operatorToken, positionInfo)) {
1628 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1633void QQmlLSCompletion::insidePostExpression(
const DomItem &parentForContext,
1634 const QQmlLSCompletionPosition &positionInfo,
1635 BackInsertIterator result)
const
1637 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1639 const QQmlJS::SourceLocation operatorToken = regions[OperatorTokenRegion];
1641 if (beforeLocation(positionInfo, operatorToken)) {
1642 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1647void QQmlLSCompletion::insideParenthesizedExpression(
const DomItem &parentForContext,
1648 const QQmlLSCompletionPosition &positionInfo,
1649 BackInsertIterator result)
const
1651 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1653 const QQmlJS::SourceLocation leftParenthesis = regions[LeftParenthesisRegion];
1654 const QQmlJS::SourceLocation rightParenthesis = regions[RightParenthesisRegion];
1656 if (betweenLocations(leftParenthesis, positionInfo, rightParenthesis)) {
1657 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1662void QQmlLSCompletion::insideTemplateLiteral(
const DomItem &parentForContext,
1663 const QQmlLSCompletionPosition &positionInfo,
1664 BackInsertIterator result)
const
1666 Q_UNUSED(parentForContext);
1667 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1671 const QQmlLSCompletionPosition &positionInfo,
1672 BackInsertIterator result)
const
1674 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1675 const QQmlJS::SourceLocation newKeyword = regions[NewKeywordRegion];
1677 if (afterLocation(newKeyword, positionInfo)) {
1678 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1683void QQmlLSCompletion::insideNewMemberExpression(
const DomItem &parentForContext,
1684 const QQmlLSCompletionPosition &positionInfo,
1685 BackInsertIterator result)
const
1687 const auto regions = FileLocations::treeOf(parentForContext)->info().regions;
1688 const QQmlJS::SourceLocation newKeyword = regions[NewKeywordRegion];
1689 const QQmlJS::SourceLocation leftParenthesis = regions[LeftParenthesisRegion];
1690 const QQmlJS::SourceLocation rightParenthesis = regions[RightParenthesisRegion];
1692 if (betweenLocations(newKeyword, positionInfo, leftParenthesis)
1693 || betweenLocations(leftParenthesis, positionInfo, rightParenthesis)) {
1694 suggestJSExpressionCompletion(positionInfo.itemAtPosition, result);
1699void QQmlLSCompletion::signalHandlerCompletion(
const QQmlJSScope::ConstPtr &scope,
1700 QDuplicateTracker<QString> *usedNames,
1701 BackInsertIterator result)
const
1703 const auto keyValues = scope->methods().asKeyValueRange();
1704 for (
const auto &[name, method] : keyValues) {
1705 if (method.access() != QQmlJSMetaMethod::Public
1706 || method.methodType() != QQmlJSMetaMethodType::Signal) {
1709 if (usedNames && usedNames->hasSeen(name)) {
1713 CompletionItem completion;
1714 completion.label = QQmlSignalNames::signalNameToHandlerName(name).toUtf8();
1715 completion.kind = CompletionItemKind::Method;
1716 result = completion;
1721
1722
1723
1726 const CompletionContextStrings &contextStrings)
const
1728 QList<CompletionItem> result;
1729 collectCompletions(currentItem, contextStrings, std::back_inserter(result));
1734 const CompletionContextStrings &contextStrings,
1735 BackInsertIterator result)
const
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758 const QQmlLSCompletionPosition positionInfo{ currentItem, contextStrings };
1759 for (DomItem currentParent = currentItem; currentParent;
1760 currentParent = currentParent.directParent()) {
1761 const DomType currentType = currentParent.internalKind();
1763 switch (currentType) {
1767 case DomType::Pragma:
1768 insidePragmaCompletion(currentParent, positionInfo, result);
1770 case DomType::ScriptType: {
1771 if (currentParent.directParent().internalKind() == DomType::QmlObject) {
1772 insideQmlObjectCompletion(currentParent.directParent(), positionInfo, result);
1776 LocalSymbolsTypes options;
1777 options.setFlag(LocalSymbolsType::ObjectType);
1778 options.setFlag(LocalSymbolsType::ValueType);
1779 suggestReachableTypes(currentItem, options, CompletionItemKind::Class, result);
1782 case DomType::ScriptFormalParameter:
1785 case DomType::Binding:
1786 insideBindingCompletion(currentParent, positionInfo, result);
1788 case DomType::Import:
1789 insideImportCompletion(currentParent, positionInfo, result);
1791 case DomType::ScriptForStatement:
1792 insideForStatementCompletion(currentParent, positionInfo, result);
1794 case DomType::ScriptBlockStatement:
1795 suggestJSStatementCompletion(positionInfo.itemAtPosition, result);
1797 case DomType::QmlFile:
1798 insideQmlFileCompletion(currentParent, positionInfo, result);
1800 case DomType::QmlObject:
1801 insideQmlObjectCompletion(currentParent, positionInfo, result);
1803 case DomType::MethodInfo:
1806 case DomType::PropertyDefinition:
1807 insidePropertyDefinitionCompletion(currentParent, positionInfo, result);
1809 case DomType::ScriptBinaryExpression:
1811 if (QQmlLSUtils::isFieldMemberExpression(currentParent))
1813 insideBinaryExpressionCompletion(currentParent, positionInfo, result);
1815 case DomType::ScriptLiteral:
1816 insideScriptLiteralCompletion(currentParent, positionInfo, result);
1818 case DomType::ScriptRegExpLiteral:
1821 case DomType::ScriptCallExpression:
1822 insideCallExpression(currentParent, positionInfo, result);
1824 case DomType::ScriptIfStatement:
1825 insideIfStatement(currentParent, positionInfo, result);
1827 case DomType::ScriptReturnStatement:
1828 insideReturnStatement(currentParent, positionInfo, result);
1830 case DomType::ScriptWhileStatement:
1831 insideWhileStatement(currentParent, positionInfo, result);
1833 case DomType::ScriptDoWhileStatement:
1834 insideDoWhileStatement(currentParent, positionInfo, result);
1836 case DomType::ScriptForEachStatement:
1837 insideForEachStatement(currentParent, positionInfo, result);
1839 case DomType::ScriptTryCatchStatement:
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1859 case DomType::ScriptSwitchStatement:
1860 insideSwitchStatement(currentParent, positionInfo, result);
1862 case DomType::ScriptCaseClause:
1863 insideCaseClause(currentParent, positionInfo, result);
1865 case DomType::ScriptDefaultClause:
1866 if (ctxBeforeStatement(positionInfo, currentParent, QQmlJS::Dom::DefaultKeywordRegion))
1868 insideDefaultClause(currentParent, positionInfo, result);
1870 case DomType::ScriptCaseBlock:
1871 insideCaseBlock(currentParent, positionInfo, result);
1873 case DomType::ScriptVariableDeclaration:
1878 case DomType::ScriptVariableDeclarationEntry:
1879 insideVariableDeclarationEntry(currentParent, positionInfo, result);
1881 case DomType::ScriptProperty:
1884 case DomType::ScriptPattern:
1885 insideScriptPattern(currentParent, positionInfo, result);
1887 case DomType::ScriptThrowStatement:
1888 insideThrowStatement(currentParent, positionInfo, result);
1890 case DomType::ScriptLabelledStatement:
1891 insideLabelledStatement(currentParent, positionInfo, result);
1893 case DomType::ScriptContinueStatement:
1894 insideContinueStatement(currentParent, positionInfo, result);
1896 case DomType::ScriptBreakStatement:
1897 insideBreakStatement(currentParent, positionInfo, result);
1899 case DomType::ScriptConditionalExpression:
1900 insideConditionalExpression(currentParent, positionInfo, result);
1902 case DomType::ScriptUnaryExpression:
1903 insideUnaryExpression(currentParent, positionInfo, result);
1905 case DomType::ScriptPostExpression:
1906 insidePostExpression(currentParent, positionInfo, result);
1908 case DomType::ScriptParenthesizedExpression:
1909 insideParenthesizedExpression(currentParent, positionInfo, result);
1911 case DomType::ScriptTemplateLiteral:
1912 insideTemplateLiteral(currentParent, positionInfo, result);
1914 case DomType::ScriptTemplateStringPart:
1917 case DomType::ScriptNewExpression:
1918 insideNewExpression(currentParent, positionInfo, result);
1920 case DomType::ScriptNewMemberExpression:
1921 insideNewMemberExpression(currentParent, positionInfo, result);
1923 case DomType::ScriptThisExpression:
1926 case DomType::ScriptSuperLiteral:
1929 case DomType::Comment:
1935 case DomType::ScriptArray:
1936 case DomType::ScriptObject:
1937 case DomType::ScriptElision:
1938 case DomType::ScriptArrayEntry:
1948 qCDebug(QQmlLSUtilsLog) <<
"No completion was found for current request.";
1954 const auto keys = pluginLoader.metaDataKeys();
1955 for (qsizetype i = 0; i < keys.size(); ++i) {
1956 auto instance = std::unique_ptr<QQmlLSPlugin>(
1957 qobject_cast<QQmlLSPlugin *>(pluginLoader.instance(i)));
1960 if (
auto completionInstance = instance->createCompletionPlugin())
1961 m_plugins.push_back(std::move(completionInstance));
1966
1967
1968
1969void QQmlLSCompletion::collectFromPlugins(qxp::function_ref<CompletionFromPluginFunction> f,
1970 BackInsertIterator result)
const
1972 for (
const auto &plugin : m_plugins) {
1974 f(plugin.get(), result);
1978void QQmlLSCompletion::suggestSnippetsForLeftHandSideOfBinding(
const DomItem &itemAtPosition,
1979 BackInsertIterator result)
const
1982 [&itemAtPosition](QQmlLSCompletionPlugin *p, BackInsertIterator result) {
1983 p->suggestSnippetsForLeftHandSideOfBinding(itemAtPosition, result);
1988void QQmlLSCompletion::suggestSnippetsForRightHandSideOfBinding(
const DomItem &itemAtPosition,
1989 BackInsertIterator result)
const
1992 [&itemAtPosition](QQmlLSCompletionPlugin *p, BackInsertIterator result) {
1993 p->suggestSnippetsForRightHandSideOfBinding(itemAtPosition, result);
QQmlLSCompletion provides completions for all kinds of QML and JS constructs.
QList< CompletionItem > completions(const DomItem ¤tItem, const CompletionContextStrings &ctx) const
QQmlLSCompletion(const QFactoryLoader &pluginLoader)
Combined button and popup list for selecting options.
void collectFromAllJavaScriptParents(const F &&f, const QQmlJSScope::ConstPtr &scope)
static const QQmlJSScope * resolve(const QQmlJSScope *current, const QStringList &names)
static void collectLabels(const DomItem &context, QQmlLSCompletion::BackInsertIterator result)
static bool testScopeSymbol(const QQmlJSScope::ConstPtr &scope, LocalSymbolsTypes options, CompletionItemKind kind)