diff options
author | Marco Bubke <marco.bubke@qt.io> | 2022-04-19 13:06:53 +0200 |
---|---|---|
committer | Marco Bubke <marco.bubke@qt.io> | 2022-04-21 09:30:47 +0000 |
commit | 697fd3ac5caea3a79e2377abcaff1c332bc2c67e (patch) | |
tree | 943b4be0ca514938b9bf9549e5b07edcd6596d13 | |
parent | 7c5dc9710263fd20cbd77d6fb37782f40b803cd3 (diff) | |
download | qt-creator-697fd3ac5caea3a79e2377abcaff1c332bc2c67e.tar.gz |
QmlDesigner: Workaround missing qualifications in parameter types
Task-number: QDS-6767
Change-Id: Ic1a34c206a7c4f6ec2be5bf5fbd25ead591fd008
Reviewed-by: Henning Gründl <henning.gruendl@qt.io>
-rw-r--r-- | src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp | 104 | ||||
-rw-r--r-- | tests/unit/unittest/qmltypesparser-test.cpp | 84 |
2 files changed, 160 insertions, 28 deletions
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp index fafca530bf..9d8e41d981 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp @@ -44,6 +44,29 @@ namespace QmlDom = QQmlJS::Dom; namespace { +using ComponentWithoutNamespaces = QMap<QString, QString>; + +ComponentWithoutNamespaces createComponentNameWithoutNamespaces( + const QHash<QString, QQmlJSScope::Ptr> &objects) +{ + ComponentWithoutNamespaces componentWithoutNamespaces; + + for (auto current = objects.keyBegin(), end = objects.keyEnd(); current != end; ++current) { + const QString &key = *current; + QString searchTerm{"::"}; + + auto found = std::search(key.cbegin(), key.cend(), searchTerm.cbegin(), searchTerm.cend()); + + if (found == key.cend()) + continue; + + componentWithoutNamespaces.insert(QStringView{std::next(found, 2), key.cend()}.toString(), + key); + } + + return componentWithoutNamespaces; +} + void appendImports(Storage::Imports &imports, const QString &dependency, SourceId sourceId, @@ -162,14 +185,28 @@ struct EnumerationType using EnumerationTypes = std::vector<EnumerationType>; -Storage::PropertyDeclarations createProperties(const QHash<QString, QQmlJSMetaProperty> &qmlProperties, - const EnumerationTypes &enumerationTypes) +Utils::SmallString fullyQualifiedTypeName(const QString &typeName, + const ComponentWithoutNamespaces &componentNameWithoutNamespace) +{ + if (auto found = componentNameWithoutNamespace.find(typeName); + found != componentNameWithoutNamespace.end()) + return found.value(); + + return typeName; +} + +Storage::PropertyDeclarations createProperties( + const QHash<QString, QQmlJSMetaProperty> &qmlProperties, + const EnumerationTypes &enumerationTypes, + const ComponentWithoutNamespaces &componentNameWithoutNamespace) { Storage::PropertyDeclarations propertyDeclarations; propertyDeclarations.reserve(Utils::usize(qmlProperties)); for (const QQmlJSMetaProperty &qmlProperty : qmlProperties) { - Utils::SmallString propertyTypeName{qmlProperty.typeName()}; + Utils::SmallString propertyTypeName{ + fullyQualifiedTypeName(qmlProperty.typeName(), componentNameWithoutNamespace)}; + auto found = find_if(enumerationTypes.begin(), enumerationTypes.end(), [&](auto &entry) { return entry.name == propertyTypeName; }); @@ -185,7 +222,8 @@ Storage::PropertyDeclarations createProperties(const QHash<QString, QQmlJSMetaPr return propertyDeclarations; } -Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMethod) +Storage::ParameterDeclarations createParameters( + const QQmlJSMetaMethod &qmlMethod, const ComponentWithoutNamespaces &componentNameWithoutNamespace) { Storage::ParameterDeclarations parameterDeclarations; @@ -198,14 +236,16 @@ Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMetho for (; currentName != nameEnd && currentType != typeEnd; ++currentName, ++currentType) { parameterDeclarations.emplace_back(Utils::SmallString{*currentName}, - Utils::SmallString{*currentType}); + fullyQualifiedTypeName(*currentType, + componentNameWithoutNamespace)); } return parameterDeclarations; } std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> createFunctionAndSignals( - const QMultiHash<QString, QQmlJSMetaMethod> &qmlMethods) + const QMultiHash<QString, QQmlJSMetaMethod> &qmlMethods, + const ComponentWithoutNamespaces &componentNameWithoutNamespace) { std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> functionAndSignalDeclarations; Storage::FunctionDeclarations &functionsDeclarations{std::get<0>(functionAndSignalDeclarations)}; @@ -216,11 +256,13 @@ std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> createFun for (const QQmlJSMetaMethod &qmlMethod : qmlMethods) { if (qmlMethod.methodType() != QQmlJSMetaMethod::Type::Signal) { functionsDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()}, - Utils::SmallString{qmlMethod.returnTypeName()}, - createParameters(qmlMethod)); + fullyQualifiedTypeName(qmlMethod.returnTypeName(), + componentNameWithoutNamespace), + createParameters(qmlMethod, + componentNameWithoutNamespace)); } else { signalDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()}, - createParameters(qmlMethod)); + createParameters(qmlMethod, componentNameWithoutNamespace)); } } @@ -279,9 +321,7 @@ EnumerationTypes addEnumerationTypes(Storage::Types &types, Utils::SmallStringView typeName, SourceId sourceId, ModuleId cppModuleId, - QmlTypesParser::ProjectStorage &storage, - const QHash<QString, QQmlJSMetaEnum> &qmlEnumerations, - const QList<QQmlJSScope::Export> &qmlExports) + const QHash<QString, QQmlJSMetaEnum> &qmlEnumerations) { EnumerationTypes enumerationTypes; enumerationTypes.reserve(Utils::usize(qmlEnumerations)); @@ -289,14 +329,11 @@ EnumerationTypes addEnumerationTypes(Storage::Types &types, for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) { Utils::SmallString enumerationName{qmlEnumeration.name()}; auto fullTypeName = Utils::SmallString::join({typeName, "::", enumerationName}); - auto &type = types.emplace_back(fullTypeName, - Storage::ImportedType{Utils::SmallString{}}, - Storage::TypeAccessSemantics::Value - | Storage::TypeAccessSemantics::IsEnum, - sourceId, - createCppEnumerationExports(typeName, - cppModuleId, - enumerationName)); + types.emplace_back(fullTypeName, + Storage::ImportedType{Utils::SmallString{}}, + Storage::TypeAccessSemantics::Value | Storage::TypeAccessSemantics::IsEnum, + sourceId, + createCppEnumerationExports(typeName, cppModuleId, enumerationName)); enumerationTypes.emplace_back(enumerationName, std::move(fullTypeName)); } @@ -307,21 +344,24 @@ void addType(Storage::Types &types, SourceId sourceId, ModuleId cppModuleId, const QQmlJSScope &component, - QmlTypesParser::ProjectStorage &storage) + QmlTypesParser::ProjectStorage &storage, + const ComponentWithoutNamespaces &componentNameWithoutNamespace) { - auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals(component.ownMethods()); + auto [functionsDeclarations, signalDeclarations] = createFunctionAndSignals( + component.ownMethods(), componentNameWithoutNamespace); Utils::SmallString typeName{component.internalName()}; auto enumerations = component.ownEnumerations(); auto exports = component.exports(); - auto enumerationTypes = addEnumerationTypes( - types, typeName, sourceId, cppModuleId, storage, enumerations, exports); + auto enumerationTypes = addEnumerationTypes(types, typeName, sourceId, cppModuleId, enumerations); types.emplace_back(Utils::SmallStringView{typeName}, Storage::ImportedType{Utils::SmallString{component.baseTypeName()}}, createTypeAccessSemantics(component.accessSemantics()), sourceId, createExports(exports, typeName, storage, cppModuleId), - createProperties(component.ownProperties(), enumerationTypes), + createProperties(component.ownProperties(), + enumerationTypes, + componentNameWithoutNamespace), std::move(functionsDeclarations), std::move(signalDeclarations), createEnumeration(enumerations)); @@ -330,12 +370,18 @@ void addType(Storage::Types &types, void addTypes(Storage::Types &types, const Storage::ProjectData &projectData, const QHash<QString, QQmlJSScope::Ptr> &objects, - QmlTypesParser::ProjectStorage &storage) + QmlTypesParser::ProjectStorage &storage, + const ComponentWithoutNamespaces &componentNameWithoutNamespaces) { types.reserve(Utils::usize(objects) + types.size()); for (const auto &object : objects) - addType(types, projectData.sourceId, projectData.moduleId, *object.get(), storage); + addType(types, + projectData.sourceId, + projectData.moduleId, + *object.get(), + storage, + componentNameWithoutNamespaces); } } // namespace @@ -352,8 +398,10 @@ void QmlTypesParser::parse(const QString &sourceContent, if (!isValid) throw CannotParseQmlTypesFile{}; + auto componentNameWithoutNamespaces = createComponentNameWithoutNamespaces(components); + addImports(imports, projectData.sourceId, dependencies, m_storage, projectData.moduleId); - addTypes(types, projectData, components, m_storage); + addTypes(types, projectData, components, m_storage, componentNameWithoutNamespaces); } } // namespace QmlDesigner diff --git a/tests/unit/unittest/qmltypesparser-test.cpp b/tests/unit/unittest/qmltypesparser-test.cpp index 28e907a297..cfb608e5ce 100644 --- a/tests/unit/unittest/qmltypesparser-test.cpp +++ b/tests/unit/unittest/qmltypesparser-test.cpp @@ -276,6 +276,34 @@ TEST_F(QmlTypesParser, Properties) | Storage::PropertyDeclarationTraits::IsPointer))))); } +TEST_F(QmlTypesParser, PropertiesWithQualifiedTypes) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + Component { name: "Qt::Vector" } + Component { name: "Qt::List" } + Component { name: "QObject" + Property { name: "values"; type: "Vector" } + Property { name: "items"; type: "List" } + Property { name: "values2"; type: "Qt::Vector" } + }})"}; + + parser.parse(source, imports, types, projectData); + + ASSERT_THAT(types, + Contains(Field(&Storage::Type::propertyDeclarations, + UnorderedElementsAre( + IsPropertyDeclaration("values", + Storage::ImportedType{"Qt::Vector"}, + Storage::PropertyDeclarationTraits::None), + IsPropertyDeclaration("items", + Storage::ImportedType{"Qt::List"}, + Storage::PropertyDeclarationTraits::None), + IsPropertyDeclaration("values2", + Storage::ImportedType{"Qt::Vector"}, + Storage::PropertyDeclarationTraits::None))))); +} + TEST_F(QmlTypesParser, Functions) { QString source{R"(import QtQuick.tooling 1.2 @@ -318,6 +346,34 @@ TEST_F(QmlTypesParser, Functions) Field(&Storage::FunctionDeclaration::parameters, IsEmpty())))))); } +TEST_F(QmlTypesParser, FunctionsWithQualifiedTypes) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + Component { name: "Qt::Vector" } + Component { name: "Qt::List" } + Component { name: "QObject" + Method { + name: "values" + Parameter { name: "values"; type: "Vector" } + Parameter { name: "items"; type: "List" } + Parameter { name: "values2"; type: "Qt::Vector" } + } + }})"}; + + parser.parse(source, imports, types, projectData); + + ASSERT_THAT(types, + Contains( + Field(&Storage::Type::functionDeclarations, + UnorderedElementsAre(AllOf( + IsFunctionDeclaration("values", ""), + Field(&Storage::FunctionDeclaration::parameters, + UnorderedElementsAre(IsParameter("values", "Qt::Vector"), + IsParameter("items", "Qt::List"), + IsParameter("values2", "Qt::Vector")))))))); +} + TEST_F(QmlTypesParser, Signals) { QString source{R"(import QtQuick.tooling 1.2 @@ -357,6 +413,34 @@ TEST_F(QmlTypesParser, Signals) IsParameter("args", "QQmlV4Function")))))))); } +TEST_F(QmlTypesParser, SignalsWithQualifiedTypes) +{ + QString source{R"(import QtQuick.tooling 1.2 + Module{ + Component { name: "Qt::Vector" } + Component { name: "Qt::List" } + Component { name: "QObject" + Signal { + name: "values" + Parameter { name: "values"; type: "Vector" } + Parameter { name: "items"; type: "List" } + Parameter { name: "values2"; type: "Qt::Vector" } + } + }})"}; + + parser.parse(source, imports, types, projectData); + + ASSERT_THAT(types, + Contains( + Field(&Storage::Type::signalDeclarations, + UnorderedElementsAre(AllOf( + IsSignalDeclaration("values"), + Field(&Storage::SignalDeclaration::parameters, + UnorderedElementsAre(IsParameter("values", "Qt::Vector"), + IsParameter("items", "Qt::List"), + IsParameter("values2", "Qt::Vector")))))))); +} + TEST_F(QmlTypesParser, Enumerations) { QString source{R"(import QtQuick.tooling 1.2 |