forked from qt-creator/qt-creator
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:
@@ -44,6 +44,29 @@ namespace QmlDom = QQmlJS::Dom;
|
|||||||
|
|
||||||
namespace {
|
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,
|
void appendImports(Storage::Imports &imports,
|
||||||
const QString &dependency,
|
const QString &dependency,
|
||||||
SourceId sourceId,
|
SourceId sourceId,
|
||||||
@@ -162,14 +185,28 @@ struct EnumerationType
|
|||||||
|
|
||||||
using EnumerationTypes = std::vector<EnumerationType>;
|
using EnumerationTypes = std::vector<EnumerationType>;
|
||||||
|
|
||||||
Storage::PropertyDeclarations createProperties(const QHash<QString, QQmlJSMetaProperty> &qmlProperties,
|
Utils::SmallString fullyQualifiedTypeName(const QString &typeName,
|
||||||
const EnumerationTypes &enumerationTypes)
|
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;
|
Storage::PropertyDeclarations propertyDeclarations;
|
||||||
propertyDeclarations.reserve(Utils::usize(qmlProperties));
|
propertyDeclarations.reserve(Utils::usize(qmlProperties));
|
||||||
|
|
||||||
for (const QQmlJSMetaProperty &qmlProperty : 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) {
|
auto found = find_if(enumerationTypes.begin(), enumerationTypes.end(), [&](auto &entry) {
|
||||||
return entry.name == propertyTypeName;
|
return entry.name == propertyTypeName;
|
||||||
});
|
});
|
||||||
@@ -185,7 +222,8 @@ Storage::PropertyDeclarations createProperties(const QHash<QString, QQmlJSMetaPr
|
|||||||
return propertyDeclarations;
|
return propertyDeclarations;
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMethod)
|
Storage::ParameterDeclarations createParameters(
|
||||||
|
const QQmlJSMetaMethod &qmlMethod, const ComponentWithoutNamespaces &componentNameWithoutNamespace)
|
||||||
{
|
{
|
||||||
Storage::ParameterDeclarations parameterDeclarations;
|
Storage::ParameterDeclarations parameterDeclarations;
|
||||||
|
|
||||||
@@ -198,14 +236,16 @@ Storage::ParameterDeclarations createParameters(const QQmlJSMetaMethod &qmlMetho
|
|||||||
|
|
||||||
for (; currentName != nameEnd && currentType != typeEnd; ++currentName, ++currentType) {
|
for (; currentName != nameEnd && currentType != typeEnd; ++currentName, ++currentType) {
|
||||||
parameterDeclarations.emplace_back(Utils::SmallString{*currentName},
|
parameterDeclarations.emplace_back(Utils::SmallString{*currentName},
|
||||||
Utils::SmallString{*currentType});
|
fullyQualifiedTypeName(*currentType,
|
||||||
|
componentNameWithoutNamespace));
|
||||||
}
|
}
|
||||||
|
|
||||||
return parameterDeclarations;
|
return parameterDeclarations;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> createFunctionAndSignals(
|
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;
|
std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> functionAndSignalDeclarations;
|
||||||
Storage::FunctionDeclarations &functionsDeclarations{std::get<0>(functionAndSignalDeclarations)};
|
Storage::FunctionDeclarations &functionsDeclarations{std::get<0>(functionAndSignalDeclarations)};
|
||||||
@@ -216,11 +256,13 @@ std::tuple<Storage::FunctionDeclarations, Storage::SignalDeclarations> createFun
|
|||||||
for (const QQmlJSMetaMethod &qmlMethod : qmlMethods) {
|
for (const QQmlJSMetaMethod &qmlMethod : qmlMethods) {
|
||||||
if (qmlMethod.methodType() != QQmlJSMetaMethod::Type::Signal) {
|
if (qmlMethod.methodType() != QQmlJSMetaMethod::Type::Signal) {
|
||||||
functionsDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()},
|
functionsDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()},
|
||||||
Utils::SmallString{qmlMethod.returnTypeName()},
|
fullyQualifiedTypeName(qmlMethod.returnTypeName(),
|
||||||
createParameters(qmlMethod));
|
componentNameWithoutNamespace),
|
||||||
|
createParameters(qmlMethod,
|
||||||
|
componentNameWithoutNamespace));
|
||||||
} else {
|
} else {
|
||||||
signalDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()},
|
signalDeclarations.emplace_back(Utils::SmallString{qmlMethod.methodName()},
|
||||||
createParameters(qmlMethod));
|
createParameters(qmlMethod, componentNameWithoutNamespace));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,9 +321,7 @@ EnumerationTypes addEnumerationTypes(Storage::Types &types,
|
|||||||
Utils::SmallStringView typeName,
|
Utils::SmallStringView typeName,
|
||||||
SourceId sourceId,
|
SourceId sourceId,
|
||||||
ModuleId cppModuleId,
|
ModuleId cppModuleId,
|
||||||
QmlTypesParser::ProjectStorage &storage,
|
const QHash<QString, QQmlJSMetaEnum> &qmlEnumerations)
|
||||||
const QHash<QString, QQmlJSMetaEnum> &qmlEnumerations,
|
|
||||||
const QList<QQmlJSScope::Export> &qmlExports)
|
|
||||||
{
|
{
|
||||||
EnumerationTypes enumerationTypes;
|
EnumerationTypes enumerationTypes;
|
||||||
enumerationTypes.reserve(Utils::usize(qmlEnumerations));
|
enumerationTypes.reserve(Utils::usize(qmlEnumerations));
|
||||||
@@ -289,14 +329,11 @@ EnumerationTypes addEnumerationTypes(Storage::Types &types,
|
|||||||
for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) {
|
for (const QQmlJSMetaEnum &qmlEnumeration : qmlEnumerations) {
|
||||||
Utils::SmallString enumerationName{qmlEnumeration.name()};
|
Utils::SmallString enumerationName{qmlEnumeration.name()};
|
||||||
auto fullTypeName = Utils::SmallString::join({typeName, "::", enumerationName});
|
auto fullTypeName = Utils::SmallString::join({typeName, "::", enumerationName});
|
||||||
auto &type = types.emplace_back(fullTypeName,
|
types.emplace_back(fullTypeName,
|
||||||
Storage::ImportedType{Utils::SmallString{}},
|
Storage::ImportedType{Utils::SmallString{}},
|
||||||
Storage::TypeAccessSemantics::Value
|
Storage::TypeAccessSemantics::Value | Storage::TypeAccessSemantics::IsEnum,
|
||||||
| Storage::TypeAccessSemantics::IsEnum,
|
sourceId,
|
||||||
sourceId,
|
createCppEnumerationExports(typeName, cppModuleId, enumerationName));
|
||||||
createCppEnumerationExports(typeName,
|
|
||||||
cppModuleId,
|
|
||||||
enumerationName));
|
|
||||||
enumerationTypes.emplace_back(enumerationName, std::move(fullTypeName));
|
enumerationTypes.emplace_back(enumerationName, std::move(fullTypeName));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,21 +344,24 @@ void addType(Storage::Types &types,
|
|||||||
SourceId sourceId,
|
SourceId sourceId,
|
||||||
ModuleId cppModuleId,
|
ModuleId cppModuleId,
|
||||||
const QQmlJSScope &component,
|
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()};
|
Utils::SmallString typeName{component.internalName()};
|
||||||
auto enumerations = component.ownEnumerations();
|
auto enumerations = component.ownEnumerations();
|
||||||
auto exports = component.exports();
|
auto exports = component.exports();
|
||||||
|
|
||||||
auto enumerationTypes = addEnumerationTypes(
|
auto enumerationTypes = addEnumerationTypes(types, typeName, sourceId, cppModuleId, enumerations);
|
||||||
types, typeName, sourceId, cppModuleId, storage, enumerations, exports);
|
|
||||||
types.emplace_back(Utils::SmallStringView{typeName},
|
types.emplace_back(Utils::SmallStringView{typeName},
|
||||||
Storage::ImportedType{Utils::SmallString{component.baseTypeName()}},
|
Storage::ImportedType{Utils::SmallString{component.baseTypeName()}},
|
||||||
createTypeAccessSemantics(component.accessSemantics()),
|
createTypeAccessSemantics(component.accessSemantics()),
|
||||||
sourceId,
|
sourceId,
|
||||||
createExports(exports, typeName, storage, cppModuleId),
|
createExports(exports, typeName, storage, cppModuleId),
|
||||||
createProperties(component.ownProperties(), enumerationTypes),
|
createProperties(component.ownProperties(),
|
||||||
|
enumerationTypes,
|
||||||
|
componentNameWithoutNamespace),
|
||||||
std::move(functionsDeclarations),
|
std::move(functionsDeclarations),
|
||||||
std::move(signalDeclarations),
|
std::move(signalDeclarations),
|
||||||
createEnumeration(enumerations));
|
createEnumeration(enumerations));
|
||||||
@@ -330,12 +370,18 @@ void addType(Storage::Types &types,
|
|||||||
void addTypes(Storage::Types &types,
|
void addTypes(Storage::Types &types,
|
||||||
const Storage::ProjectData &projectData,
|
const Storage::ProjectData &projectData,
|
||||||
const QHash<QString, QQmlJSScope::Ptr> &objects,
|
const QHash<QString, QQmlJSScope::Ptr> &objects,
|
||||||
QmlTypesParser::ProjectStorage &storage)
|
QmlTypesParser::ProjectStorage &storage,
|
||||||
|
const ComponentWithoutNamespaces &componentNameWithoutNamespaces)
|
||||||
{
|
{
|
||||||
types.reserve(Utils::usize(objects) + types.size());
|
types.reserve(Utils::usize(objects) + types.size());
|
||||||
|
|
||||||
for (const auto &object : objects)
|
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
|
} // namespace
|
||||||
@@ -352,8 +398,10 @@ void QmlTypesParser::parse(const QString &sourceContent,
|
|||||||
if (!isValid)
|
if (!isValid)
|
||||||
throw CannotParseQmlTypesFile{};
|
throw CannotParseQmlTypesFile{};
|
||||||
|
|
||||||
|
auto componentNameWithoutNamespaces = createComponentNameWithoutNamespaces(components);
|
||||||
|
|
||||||
addImports(imports, projectData.sourceId, dependencies, m_storage, projectData.moduleId);
|
addImports(imports, projectData.sourceId, dependencies, m_storage, projectData.moduleId);
|
||||||
addTypes(types, projectData, components, m_storage);
|
addTypes(types, projectData, components, m_storage, componentNameWithoutNamespaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -276,6 +276,34 @@ TEST_F(QmlTypesParser, Properties)
|
|||||||
| Storage::PropertyDeclarationTraits::IsPointer)))));
|
| 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)
|
TEST_F(QmlTypesParser, Functions)
|
||||||
{
|
{
|
||||||
QString source{R"(import QtQuick.tooling 1.2
|
QString source{R"(import QtQuick.tooling 1.2
|
||||||
@@ -318,6 +346,34 @@ TEST_F(QmlTypesParser, Functions)
|
|||||||
Field(&Storage::FunctionDeclaration::parameters, IsEmpty()))))));
|
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)
|
TEST_F(QmlTypesParser, Signals)
|
||||||
{
|
{
|
||||||
QString source{R"(import QtQuick.tooling 1.2
|
QString source{R"(import QtQuick.tooling 1.2
|
||||||
@@ -357,6 +413,34 @@ TEST_F(QmlTypesParser, Signals)
|
|||||||
IsParameter("args", "QQmlV4Function"))))))));
|
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)
|
TEST_F(QmlTypesParser, Enumerations)
|
||||||
{
|
{
|
||||||
QString source{R"(import QtQuick.tooling 1.2
|
QString source{R"(import QtQuick.tooling 1.2
|
||||||
|
Reference in New Issue
Block a user