QmlDesigner: Workaround missing qualifications in parameter types

Task-number: QDS-6767
Change-Id: Ic1a34c206a7c4f6ec2be5bf5fbd25ead591fd008
Reviewed-by: Henning Gründl <henning.gruendl@qt.io>
This commit is contained in:
Marco Bubke
2022-04-19 13:06:53 +02:00
parent 7c5dc97102
commit 697fd3ac5c
2 changed files with 160 additions and 28 deletions

View File

@@ -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,
types.emplace_back(fullTypeName,
Storage::ImportedType{Utils::SmallString{}},
Storage::TypeAccessSemantics::Value
| Storage::TypeAccessSemantics::IsEnum,
Storage::TypeAccessSemantics::Value | Storage::TypeAccessSemantics::IsEnum,
sourceId,
createCppEnumerationExports(typeName,
cppModuleId,
enumerationName));
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

View File

@@ -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