QmlJS: Add error message for Component with multiple children

Component is only allowed to have a single child element, that will
be the root element of the component.

If there is no child at all we create a warning. Having no child is
temporarily required.

Change-Id: I5c0d9d9cdf1be106b20ed4f1134a973d58126498
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Thomas Hartmann
2021-09-28 15:23:42 +02:00
parent ebc753cf9b
commit 39738dee77
4 changed files with 31 additions and 3 deletions

View File

@@ -794,8 +794,10 @@ bool Check::visit(UiObjectInitializer *)
UiQualifiedId *qualifiedTypeId = qualifiedTypeNameId(parent());
if (qualifiedTypeId) {
typeName = qualifiedTypeId->name.toString();
if (typeName == "Component")
if (typeName == "Component") {
m_idStack.push(StringSet());
_componentChildCount = 0;
}
}
m_typeStack.push(typeName);
@@ -806,10 +808,23 @@ bool Check::visit(UiObjectInitializer *)
return true;
}
void Check::endVisit(UiObjectInitializer *)
void Check::endVisit(UiObjectInitializer *uiObjectInitializer)
{
m_propertyStack.pop();
m_typeStack.pop();
const QString type = m_typeStack.pop();
if (type == "Component" && _componentChildCount == 0) {
SourceLocation loc;
UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(parent());
if (objectDefinition)
loc = objectDefinition->qualifiedTypeNameId->identifierToken;
UiObjectBinding *objectBinding = cast<UiObjectBinding *>(parent());
if (objectBinding)
loc = objectBinding->qualifiedTypeNameId->identifierToken;
addMessage(WarnComponentRequiresChildren, loc);
}
UiObjectDefinition *objectDefinition = cast<UiObjectDefinition *>(parent());
if (objectDefinition && objectDefinition->qualifiedTypeNameId->name == QLatin1String("Component"))
m_idStack.pop();
@@ -962,6 +977,12 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
addMessage(ErrUnsupportedRootTypeInQmlUi,
locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation()), typeName);
if (!m_typeStack.isEmpty() && m_typeStack.last() == "Component") {
_componentChildCount++;
if (_componentChildCount > 1)
addMessage(ErrToManyComponentChildren, typeErrorLocation);
}
bool typeError = false;
if (_importsOk) {
const ObjectValue *prototype = _context->lookupType(_doc.data(), typeId);

View File

@@ -158,6 +158,7 @@ private:
bool _importsOk;
bool _inStatementBinding;
int _componentChildCount = 0;
const Imports *_imports;
TranslationFunction lastTransLationfunction = noTranslationfunction;
};

View File

@@ -251,6 +251,10 @@ StaticAnalysisMessages::StaticAnalysisMessages()
tr("Type cannot be instantiated recursively (%1)."), 1);
newMsg(WarnLogicalValueDoesNotDependOnValues, Warning,
tr("Logical value does not depend on actual values"));
newMsg(ErrToManyComponentChildren, Error,
tr("Components are only allowed to have a single child element."));
newMsg(WarnComponentRequiresChildren, Warning,
tr("Components require a child element."));
}
} // anonymous namespace

View File

@@ -132,6 +132,8 @@ enum Type {
ErrInvalidArrayValueLength = 323,
ErrHitMaximumRecursion = 324,
WarnLogicalValueDoesNotDependOnValues = 325,
ErrToManyComponentChildren = 326,
WarnComponentRequiresChildren = 327,
WarnDuplicateImport = 400
};