6#include <QtLanguageServer/private/qlanguageserverspectypes_p.h>
7#include <QtCore/qthreadpool.h>
8#include <QtCore/private/qduplicatetracker_p.h>
9#include <QtCore/QRegularExpression>
10#include <QtQmlDom/private/qqmldomexternalitems_p.h>
11#include <QtQmlDom/private/qqmldomtop_p.h>
12#include <QtQmlDom/private/qqmldomscriptelements_p.h>
13#include <QtQmlDom/private/qqmldom_utils_p.h>
35 return item.internalKind() == DomType::ScriptBinaryExpression
36 &&
item.field(Fields::operation).value().toInteger()
52 return item == rightHandSide;
113 int targetLine =
row;
115 while (
i !=
text.
size() && targetLine != 0) {
129 if (
c == u
'\n' ||
c == u
'\r')
132 if (!
c.isLowSurrogate())
157 currentLineOffset =
i + 1;
158 }
else if (
c == u
'\r') {
159 if (
i > 0 &&
text[
i - 1] == u
'\n')
180 std::shared_ptr<QmlFile> filePtr =
file.ownerAs<
QmlFile>();
185 QString code = filePtr->code();
191 return l.begin() <=
quint32(targetPos) &&
quint32(targetPos) <= l.end();
193 return l.begin() <= targetPos && targetPos <= l.end();
196 if (containsTarget(
t->info().fullRegion)) {
206 bool inParentButOutsideChildren =
true;
210 auto subLoc = std::static_pointer_cast<AttachedInfoT<FileLocations>>(
it.value());
213 if (containsTarget(subLoc->info().fullRegion)) {
218 <<
"A DomItem child is missing or the FileLocationsTree structure does "
219 "not follow the DomItem Structure.";
224 inParentButOutsideChildren =
false;
227 if (inParentButOutsideChildren) {
233 if (itemsFound.
size() > 1) {
239 auto smallest = std::min_element(
240 itemsFound.
begin(), itemsFound.
end(),
242 return a.fileLocation->info().fullRegion.length
243 < b.fileLocation->info().fullRegion.length;
246 filteredItems.
append(*smallest);
250 const quint32 smallestEnd = smallestLoc.
end();
252 for (
auto it = itemsFound.
begin();
it != itemsFound.
end();
it++) {
259 if (itBegin == smallestEnd || smallestBegin == itEnd) {
263 itemsFound = filteredItems;
270 if (!
object.as<QmlObject>())
273 auto prototypes =
object.
field(QQmlJS::Dom::Fields::prototypes);
274 switch (prototypes.indexes()) {
280 qDebug() <<
"Multiple prototypes found for " <<
object.name() <<
", taking the first one.";
304 switch (
object.internalKind()) {
306 result =
object.field(Fields::objects).index(0);
312 auto binding =
object.as<
Binding>();
316 if (binding->valueKind() == BindingValueKind::Object) {
321 const QString bindingName = binding->name();
322 object.containingObject().visitLookup(
326 propertyDefinition = item;
331 LookupType::PropertyDef);
337 result =
object.field(Fields::referredObject).proceedToScope();
342 result =
object.field(Fields::type).proceedToScope();
345 if (
object.directParent().internalKind() == DomType::ScriptType) {
348 FilterUpOptions::ReturnOuter);
360 scope->sourceLocation());
365 qDebug() <<
"QQmlLSUtils::findTypeDefinitionOf: Found unimplemented Type"
366 <<
object.internalKindStr();
377 if (std::optional<QQmlJSScope::Ptr> scope =
i.semanticScope(); scope) {
378 qCDebug(QQmlLSUtilsLog) <<
"Searching for definition in" <<
i.internalKindStr();
379 if (
auto jsIdentifier = scope.value()->JSIdentifier(
name)) {
380 qCDebug(QQmlLSUtilsLog) <<
"Found scope" << scope.value()->baseTypeName();
381 definitionOfItem =
i;
386 if (
i.internalKind() == DomType::ScriptExpression)
391 return definitionOfItem;
403 bool resolveType =
false;
404 bool continueForChildren =
true;
405 DomItem toBeResolved = current;
408 if (
auto scope = current.semanticScope()) {
410 if (scope.value()->JSIdentifier(
name)) {
415 switch (current.internalKind()) {
416 case DomType::PropertyDefinition: {
417 const QString propertyName = current.field(Fields::name).value().toString();
418 if (
name == propertyName) {
425 case DomType::ScriptIdentifierExpression: {
426 const QString propertyName = current.field(Fields::identifier).value().toString();
427 if (
name != propertyName)
433 case DomType::MethodInfo: {
438 subRegion = u
"identifier"_s;
449 qCDebug(QQmlLSUtilsLog) <<
"Will resolve type of" << toBeResolved.internalKindStr();
450 if (currentType == targetType) {
455 sourceLocation = tree->info().fullRegion;
457 auto regions = tree->info().regions;
460 return continueForChildren;
461 sourceLocation = *
it;
468 return continueForChildren;
471 item.containingFile()
472 .field(Fields::components)
479 qCDebug(QQmlLSUtilsLog) <<
"Looking for JS identifier with name" <<
name;
483 if (!definitionOfItem) {
484 qCDebug(QQmlLSUtilsLog) <<
"No defining JS-Scope found!";
489 definitionOfItem.visitTree(
492 qCDebug(QQmlLSUtilsLog) <<
"Visiting a " <<
item.internalKindStr();
493 if (
item.internalKind() == DomType::ScriptIdentifierExpression
494 &&
item.field(Fields::identifier).value().toString() ==
name) {
498 qCWarning(QQmlLSUtilsLog) <<
"Failed finding filelocation of found usage";
505 }
else if (std::optional<QQmlJSScope::Ptr> scope =
item.semanticScope();
506 scope && scope.value()->JSIdentifier(
name)) {
518 switch (
item.internalKind()) {
519 case DomType::ScriptIdentifierExpression: {
520 const QString name =
item.field(Fields::identifier).value().toString();
524 case DomType::ScriptVariableDeclarationEntry: {
525 const QString name =
item.field(Fields::identifier).value().toString();
529 case DomType::PropertyDefinition:
530 case DomType::MethodInfo: {
537 <<
"was not implemented for QQmlLSUtils::findUsagesOf";
543 if (QQmlLSUtilsLog().isDebugEnabled()) {
544 qCDebug(QQmlLSUtilsLog) <<
"Found following usages:";
547 <<
r.filename <<
" @ " <<
r.location.startLine <<
":" <<
r.location.startColumn
548 <<
" with length " <<
r.location.length;
559 if (current->hasMethod(
name)) {
571 if (
auto property = current->property(propertyName);
property.isValid()) {
576 return property.type();
591 switch (
item.internalKind()) {
592 case DomType::ScriptIdentifierExpression: {
593 auto referrerScope =
item.nearestSemanticScope();
597 const QString name =
item.field(Fields::identifier).value().toString();
604 if (owner->hasMethod(
name)) {
616 if (
auto property = owner->property(
name);
property.isValid()) {
621 return property.type();
629 if (definitionOfItem) {
635 "QQmlLSUtils::findDefinitionOf",
636 "JS definition does not actually define the JS identifer. "
637 "It should be empty.");
638 auto scope = definitionOfItem.
semanticScope().value()->JSIdentifier(
name)->scope.toStrongRef();;
654 auto resolver =
item.containingFile().ownerAs<
QmlFile>()->typeResolver();
663 case DomType::PropertyDefinition: {
665 if (propertyDefinition && propertyDefinition->scope) {
668 return propertyDefinition->scope.value();
670 return propertyDefinition->scope.value()->property(propertyDefinition->name).type();
676 case DomType::QmlObject: {
678 if (
object &&
object->semanticScope())
683 case DomType::MethodInfo: {
685 if (
object &&
object->semanticScope())
691 case DomType::ScriptBinaryExpression: {
695 item.field(Fields::right).field(Fields::identifier).value().toString();
704 return ownerType->property(propertyName).type();
710 qCDebug(QQmlLSUtilsLog) <<
"Type" <<
item.internalKindStr()
711 <<
"is unimplemented in QQmlLSUtils::resolveExpressionType";
736 == second.fileLocation->info().fullRegion.startLine,
737 "QQmlLSUtils::findTypeDefinitionOf(DomItem)",
738 "QQmlLSUtils::itemsFromTextLocation returned non-adjacent items.");
739 if (
first.fileLocation->info().fullRegion.startColumn
740 > second.fileLocation->info().fullRegion.startColumn)
741 return first.domItem;
743 return second.domItem;
747 qDebug() <<
"Found multiple candidates for type of scriptidentifierexpression";
753static std::optional<QQmlLSUtilsLocation>
762 auto regions = fileLocation->info().regions;
774static std::optional<QQmlLSUtilsLocation>
779 DomItem propertyDefinition = propertyOwner.field(Fields::propertyDefs).key(
name).index(0);
780 if (!propertyDefinition)
785 result.filename = propertyDefinition.canonicalFilePath();
792 switch (
item.internalKind()) {
798 const DomItem ownerFile =
item.goToFile(ownerScope->filePath());
800 if (
auto methodDefinition =
802 return methodDefinition;
804 if (
auto propertyDefinition =
806 return propertyDefinition;
814 Q_ASSERT_X(definitionOfItem.semanticScope().has_value()
815 && definitionOfItem.semanticScope()
819 "QQmlLSUtils::findDefinitionOf",
820 "JS definition does not actually define the JS identifer. "
821 "It should be empty.");
823 definitionOfItem.semanticScope().value()->JSIdentifier(
name).value().location;
830 auto referrerScope =
item.nearestSemanticScope();
849 auto resolver =
item.containingFile().ownerAs<
QmlFile>()->typeResolver();
862 qDebug() <<
"QQmlLSUtils::findDefinitionOf: Found unimplemented Type "
863 <<
item.internalKindStr();
867 Q_UNREACHABLE_RETURN(std::nullopt);
qsizetype size() const noexcept
bool isEmpty() const noexcept
void removeLast() noexcept
void append(parameter_type t)
QQmlJSScope::Ptr parentScope()
QQmlJS::SourceLocation sourceLocation() const
DomItem proceedToScope(ErrorHandler h=nullptr, QList< Path > *visitedRefs=nullptr)
std::optional< QQmlJSScope::Ptr > semanticScope()
DomItem filterUp(function_ref< bool(DomType k, DomItem &)> filter, FilterUpOptions options)
DomItem path(Path p, ErrorHandler h=&defaultErrorHandler)
DomItem field(QStringView name)
static FileLocations::Tree treeOf(DomItem &)
std::shared_ptr< AttachedInfoT< FileLocations > > Tree
std::optional< QQmlJSScope::Ptr > semanticScope() const
std::optional< QQmlJSScope::Ptr > semanticScope() const
static QQmlJS::Dom::DomItem findTypeDefinitionOf(QQmlJS::Dom::DomItem item)
Extracts the QML object type of an \l DomItem.
static QQmlJS::Dom::DomItem sourceLocationToDomItem(QQmlJS::Dom::DomItem file, const QQmlJS::SourceLocation &location)
static QQmlJSScope::ConstPtr resolveExpressionType(QQmlJS::Dom::DomItem item, QQmlLSUtilsResolveOptions)
static std::optional< QQmlLSUtilsLocation > findDefinitionOf(QQmlJS::Dom::DomItem item)
static QByteArray lspUriToQmlUrl(const QByteArray &uri)
static QQmlJS::Dom::DomItem baseObject(QQmlJS::Dom::DomItem qmlObject)
static QByteArray qmlUrlToLspUri(const QByteArray &url)
static QList< QQmlLSUtilsLocation > findUsagesOf(QQmlJS::Dom::DomItem item)
static QLspSpecification::Range qmlLocationToLspLocation(const QString &code, QQmlJS::SourceLocation qmlLocation)
Converts a QQmlJS::SourceLocation to a LSP Range.
static qsizetype textOffsetFrom(const QString &code, int row, int character)
Convert a text position from (line, column) into an offset.
static QList< QQmlLSUtilsItemLocation > itemsFromTextLocation(QQmlJS::Dom::DomItem file, int line, int character)
Find the DomItem representing the object situated in file at given line and character/column.
static QQmlLSUtilsTextPosition textRowAndColumnFrom(const QString &code, qsizetype offset)
Convert a text position from an offset into (line, column).
const_iterator constEnd() const noexcept
const_iterator constFind(const T &value) const
\macro QT_RESTRICTED_CAST_FROM_ASCII
qsizetype size() const
Returns the number of characters in this string.
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
QSet< QString >::iterator it
Path lookupTypePath(QString name)
bool emptyChildrenVisitor(Path, DomItem &, bool)
@ ScriptIdentifierExpression
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
static QString methodName(const QDBusIntrospection::Method &method)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr offset
GLenum GLenum GLsizei void GLsizei void * column
GLenum GLenum GLsizei void * row
static void findUsagesHelper(DomItem item, const QString &name, QList< QQmlLSUtilsLocation > &result)
static std::optional< QQmlLSUtilsLocation > findMethodDefinitionOf(DomItem file, QQmlJS::SourceLocation location, const QString &name)
static QT_BEGIN_NAMESPACE bool isFieldMemberExpression(DomItem &item)
static QQmlJSScope::ConstPtr findPropertyIn(const QQmlJSScope::Ptr &referrerScope, const QString &propertyName, QQmlLSUtilsResolveOptions options)
static bool isFieldMemberAccess(DomItem &item)
static DomItem findJSIdentifierDefinition(DomItem item, const QString &name)
static std::optional< QQmlLSUtilsLocation > findPropertyDefinitionOf(DomItem file, QQmlJS::SourceLocation propertyDefinitionLocation, const QString &name)
static QQmlJSScope::ConstPtr findMethodIn(const QQmlJSScope::Ptr &referrerScope, const QString &name)
static void findUsagesOfNonJSIdentifiers(DomItem item, const QString &name, QList< QQmlLSUtilsLocation > &result)
QQmlLSUtilsResolveOptions
#define Q_ASSERT_X(cond, x, msg)
static QString canonicalPath(const QString &rootPath)
QUrl url("example.com")
[constructor-url-reference]
QQmlJS::Dom::DomItem domItem
QQmlJS::Dom::FileLocations::Tree fileLocation
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent