aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlcompiler
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlcompiler')
-rw-r--r--src/qmlcompiler/qdeferredpointer_p.h6
-rw-r--r--src/qmlcompiler/qqmljsbasicblocks.cpp16
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp132
-rw-r--r--src/qmlcompiler/qqmljscodegenerator_p.h7
-rw-r--r--src/qmlcompiler/qqmljscompilepass_p.h6
-rw-r--r--src/qmlcompiler/qqmljscompiler.cpp32
-rw-r--r--src/qmlcompiler/qqmljscompiler_p.h1
-rw-r--r--src/qmlcompiler/qqmljsfunctioninitializer.cpp4
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp10
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp44
-rw-r--r--src/qmlcompiler/qqmljslinter.cpp34
-rw-r--r--src/qmlcompiler/qqmljslintercodegen.cpp1
-rw-r--r--src/qmlcompiler/qqmljsloadergenerator.cpp8
-rw-r--r--src/qmlcompiler/qqmljslogger.cpp6
-rw-r--r--src/qmlcompiler/qqmljslogger_p.h14
-rw-r--r--src/qmlcompiler/qqmljsmetatypes_p.h8
-rw-r--r--src/qmlcompiler/qqmljsresourcefilemapper.cpp2
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp11
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h28
-rw-r--r--src/qmlcompiler/qqmljsshadowcheck.cpp8
-rw-r--r--src/qmlcompiler/qqmljsstreamwriter.cpp2
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp43
-rw-r--r--src/qmlcompiler/qqmljstypepropagator_p.h9
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp171
-rw-r--r--src/qmlcompiler/qqmljstyperesolver_p.h7
-rw-r--r--src/qmlcompiler/qqmljsutils.cpp34
-rw-r--r--src/qmlcompiler/qqmljsutils_p.h2
27 files changed, 374 insertions, 272 deletions
diff --git a/src/qmlcompiler/qdeferredpointer_p.h b/src/qmlcompiler/qdeferredpointer_p.h
index 481c0e27ae..f4d8696f69 100644
--- a/src/qmlcompiler/qdeferredpointer_p.h
+++ b/src/qmlcompiler/qdeferredpointer_p.h
@@ -50,15 +50,15 @@ public:
QDeferredSharedPointer() = default;
QDeferredSharedPointer(QSharedPointer<T> data)
- : m_data(data)
+ : m_data(std::move(data))
{}
QDeferredSharedPointer(QWeakPointer<T> data)
- : m_data(data)
+ : m_data(std::move(data))
{}
QDeferredSharedPointer(QSharedPointer<T> data, QSharedPointer<Factory> factory)
- : m_data(data), m_factory(factory)
+ : m_data(std::move(data)), m_factory(std::move(factory))
{
// You have to provide a valid pointer if you provide a factory. We cannot allocate the
// pointer for you because then two copies of the same QDeferredSharedPointer will diverge
diff --git a/src/qmlcompiler/qqmljsbasicblocks.cpp b/src/qmlcompiler/qqmljsbasicblocks.cpp
index a7bbd5326c..093b11684c 100644
--- a/src/qmlcompiler/qqmljsbasicblocks.cpp
+++ b/src/qmlcompiler/qqmljsbasicblocks.cpp
@@ -45,14 +45,14 @@ QQmlJSCompilePass::InstructionAnnotations QQmlJSBasicBlocks::run(
m_function = function;
m_annotations = annotations;
- for (int i = 0, end = function->argumentTypes.length(); i != end; ++i) {
+ for (int i = 0, end = function->argumentTypes.size(); i != end; ++i) {
InstructionAnnotation annotation;
annotation.changedRegisterIndex = FirstArgument + i;
annotation.changedRegister = function->argumentTypes[i];
m_annotations[-annotation.changedRegisterIndex] = annotation;
}
- for (int i = 0, end = function->registerTypes.length(); i != end; ++i) {
+ for (int i = 0, end = function->registerTypes.size(); i != end; ++i) {
InstructionAnnotation annotation;
annotation.changedRegisterIndex = firstRegisterIndex() + i;
annotation.changedRegister = function->registerTypes[i];
@@ -62,7 +62,7 @@ QQmlJSCompilePass::InstructionAnnotations QQmlJSBasicBlocks::run(
m_basicBlocks.insert_or_assign(m_annotations.begin().key(), BasicBlock());
const QByteArray byteCode = function->code;
- decode(byteCode.constData(), static_cast<uint>(byteCode.length()));
+ decode(byteCode.constData(), static_cast<uint>(byteCode.size()));
if (m_hadBackJumps) {
// We may have missed some connections between basic blocks if there were back jumps.
// Fill them in via a second pass.
@@ -75,7 +75,7 @@ QQmlJSCompilePass::InstructionAnnotations QQmlJSBasicBlocks::run(
}
reset();
- decode(byteCode.constData(), static_cast<uint>(byteCode.length()));
+ decode(byteCode.constData(), static_cast<uint>(byteCode.size()));
for (auto it = m_basicBlocks.begin(), end = m_basicBlocks.end(); it != end; ++it)
deduplicate(it->second.jumpOrigins);
}
@@ -415,7 +415,7 @@ void QQmlJSBasicBlocks::adjustTypes()
const InstructionAnnotation &annotation = m_annotations[instructionOffset];
- Q_ASSERT(it->trackedTypes.length() == 1);
+ Q_ASSERT(it->trackedTypes.size() == 1);
Q_ASSERT(it->trackedTypes[0] == m_typeResolver->containedType(annotation.changedRegister));
Q_ASSERT(!annotation.readRegisters.isEmpty());
@@ -430,7 +430,7 @@ void QQmlJSBasicBlocks::adjustTypes()
valueType);
}
- for (const QList<int> &conversions : qAsConst(it->registerReadersAndConversions)) {
+ for (const QList<int> &conversions : std::as_const(it->registerReadersAndConversions)) {
for (int conversion : conversions)
liveConversions[conversion].append(it->trackedRegister);
}
@@ -439,14 +439,14 @@ void QQmlJSBasicBlocks::adjustTypes()
}
for (auto it = m_readerLocations.begin(), end = m_readerLocations.end(); it != end; ++it) {
- for (const QList<int> &conversions : qAsConst(it->registerReadersAndConversions)) {
+ for (const QList<int> &conversions : std::as_const(it->registerReadersAndConversions)) {
for (int conversion : conversions)
liveConversions[conversion].append(it->trackedRegister);
}
// There is always one first occurrence of any tracked type. Conversions don't change
// the type.
- if (it->trackedTypes.length() != 1)
+ if (it->trackedTypes.size() != 1)
continue;
m_typeResolver->adjustTrackedType(it->trackedTypes[0], it->typeReaders.values());
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index f9455e7815..a14ea33e14 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -35,6 +35,15 @@ using namespace Qt::StringLiterals;
m_body += u"// "_s + QStringLiteral(#function) + u'\n'; \
}
+
+static bool isTypeStorable(const QQmlJSTypeResolver *resolver, const QQmlJSScope::ConstPtr &type)
+{
+ return !type.isNull()
+ && !resolver->equals(type, resolver->nullType())
+ && !resolver->equals(type, resolver->emptyListType())
+ && !resolver->equals(type, resolver->voidType());
+}
+
QString QQmlJSCodeGenerator::castTargetName(const QQmlJSScope::ConstPtr &type) const
{
return type->augmentedInternalName();
@@ -43,9 +52,8 @@ QString QQmlJSCodeGenerator::castTargetName(const QQmlJSScope::ConstPtr &type) c
QQmlJSCodeGenerator::QQmlJSCodeGenerator(const QV4::Compiler::Context *compilerContext,
const QV4::Compiler::JSUnitGenerator *unitGenerator,
const QQmlJSTypeResolver *typeResolver,
- QQmlJSLogger *logger, const QStringList &sourceCodeLines)
+ QQmlJSLogger *logger)
: QQmlJSCompilePass(unitGenerator, typeResolver, logger)
- , m_sourceCodeLines(sourceCodeLines)
, m_context(compilerContext)
{}
@@ -75,14 +83,6 @@ QString QQmlJSCodeGenerator::metaObject(const QQmlJSScope::ConstPtr &objectType)
return QString();
}
-static bool isTypeStorable(const QQmlJSTypeResolver *resolver, const QQmlJSScope::ConstPtr &type)
-{
- return !type.isNull()
- && !resolver->equals(type, resolver->nullType())
- && !resolver->equals(type, resolver->emptyListType())
- && !resolver->equals(type, resolver->voidType());
-}
-
QQmlJSAotFunction QQmlJSCodeGenerator::run(
const Function *function, const InstructionAnnotations *annotations,
QQmlJS::DiagnosticMessage *error)
@@ -103,7 +103,7 @@ QQmlJSAotFunction QQmlJSCodeGenerator::run(
auto &currentRegisterNames = registerNames[registerIndex];
QString &name = currentRegisterNames[m_typeResolver->comparableType(seenType)];
if (name.isEmpty())
- name = u"r%1_%2"_s.arg(registerIndex).arg(currentRegisterNames.count());
+ name = u"r%1_%2"_s.arg(registerIndex).arg(currentRegisterNames.size());
typesForRegisters[seenType] = name;
}
};
@@ -123,7 +123,7 @@ QT_WARNING_POP
// ensure we have m_labels for loops
for (const auto loopLabel : m_context->labelInfo)
- m_labels.insert(loopLabel, u"label_%1"_s.arg(m_labels.count()));
+ m_labels.insert(loopLabel, u"label_%1"_s.arg(m_labels.size()));
// Initialize the first instruction's state to hold the arguments.
// After this, the arguments (or whatever becomes of them) are carried
@@ -131,11 +131,14 @@ QT_WARNING_POP
m_state.State::operator=(initialState(m_function));
const QByteArray byteCode = function->code;
- decode(byteCode.constData(), static_cast<uint>(byteCode.length()));
+ decode(byteCode.constData(), static_cast<uint>(byteCode.size()));
QQmlJSAotFunction result;
result.includes.swap(m_includes);
+ result.code += u"// %1 at line %2, column %3\n"_s
+ .arg(m_context->name).arg(m_context->line).arg(m_context->column);
+
QDuplicateTracker<QString> generatedVariables;
for (auto registerIt = m_registerVariables.cbegin(), registerEnd = m_registerVariables.cend();
registerIt != registerEnd; ++registerIt) {
@@ -204,7 +207,7 @@ QT_WARNING_POP
result.code += m_body;
- for (const QQmlJSRegisterContent &argType : qAsConst(function->argumentTypes)) {
+ for (const QQmlJSRegisterContent &argType : std::as_const(function->argumentTypes)) {
if (argType.isValid()) {
result.argumentTypes.append(
m_typeResolver->originalType(argType.storedType())
@@ -309,17 +312,41 @@ void QQmlJSCodeGenerator::generate_LoadConst(int index)
{
INJECT_TRACE_INFO(generate_LoadConst);
- auto encodedConst = m_jsUnitGenerator->constant(index);
- double value = QV4::StaticValue::fromReturnedValue(encodedConst).doubleValue();
- m_body += m_state.accumulatorVariableOut;
+ // You cannot actually get it to generate LoadConst for anything but double. We have
+ // a numer of specialized instructions for the other types, after all. However, let's
+ // play it safe.
- // ### handle other types?
- m_body += u" = "_s + conversion(
- m_typeResolver->intType(), m_state.accumulatorOut().storedType(),
- toNumericString(value));
+ const QV4::ReturnedValue encodedConst = m_jsUnitGenerator->constant(index);
+ const QV4::StaticValue value = QV4::StaticValue::fromReturnedValue(encodedConst);
+ const QQmlJSScope::ConstPtr type = m_typeResolver->typeForConst(encodedConst);
+
+ m_body += m_state.accumulatorVariableOut + u" = "_s;
+ if (type == m_typeResolver->realType()) {
+ m_body += conversion(
+ type, m_state.accumulatorOut().storedType(),
+ toNumericString(value.doubleValue()));
+ } else if (type == m_typeResolver->intType()) {
+ m_body += conversion(
+ type, m_state.accumulatorOut().storedType(),
+ QString::number(value.integerValue()));
+ } else if (type == m_typeResolver->boolType()) {
+ m_body += conversion(
+ type, m_state.accumulatorOut().storedType(),
+ value.booleanValue() ? u"true"_s : u"false"_s);
+ } else if (type == m_typeResolver->voidType()) {
+ m_body += conversion(
+ type, m_state.accumulatorOut().storedType(),
+ QString());
+ } else if (type == m_typeResolver->nullType()) {
+ m_body += conversion(
+ type, m_state.accumulatorOut().storedType(),
+ u"nullptr"_s);
+ } else {
+ reject(u"unsupported constant type"_s);
+ }
m_body += u";\n"_s;
- generateOutputVariantConversion(m_typeResolver->intType());
+ generateOutputVariantConversion(type);
}
void QQmlJSCodeGenerator::generate_LoadZero()
@@ -2227,17 +2254,6 @@ QV4::Moth::ByteCodeHandler::Verdict QQmlJSCodeGenerator::startInstruction(
|| !m_state.accumulatorVariableOut.isEmpty()
|| !isTypeStorable(m_typeResolver, m_state.changedRegister().storedType()));
- const int currentLine = currentSourceLocation().startLine;
- if (currentLine != m_lastLineNumberUsed) {
- const int nextLine = nextJSLine(currentLine);
- for (auto line = currentLine - 1; line < nextLine - 1; ++line) {
- m_body += u"// "_s;
- m_body += m_sourceCodeLines.value(line).trimmed();
- m_body += u'\n';
- }
- m_lastLineNumberUsed = currentLine;
- }
-
// If the instruction has no side effects and doesn't write any register, it's dead.
// We might still need the label, though, and the source code comment.
if (!m_state.hasSideEffects() && changedRegisterVariable().isEmpty())
@@ -2291,9 +2307,18 @@ void QQmlJSCodeGenerator::generateEqualityOperation(int lhs, const QString &func
const auto primitive = m_typeResolver->jsPrimitiveType();
if (m_typeResolver->equals(lhsType, rhsType) && !m_typeResolver->equals(lhsType, primitive)) {
- m_body += conversion(m_typeResolver->boolType(), m_state.accumulatorOut().storedType(),
- registerVariable(lhs) + (invert ? u" != "_s : u" == "_s)
- + m_state.accumulatorVariableIn);
+ if (isTypeStorable(m_typeResolver, lhsType)) {
+ m_body += conversion(m_typeResolver->boolType(), m_state.accumulatorOut().storedType(),
+ registerVariable(lhs) + (invert ? u" != "_s : u" == "_s)
+ + m_state.accumulatorVariableIn);
+ } else if (m_typeResolver->equals(lhsType, m_typeResolver->emptyListType())) {
+ // We cannot compare two empty lists, because we don't know whether it's
+ // the same instance or not. "[] === []" is false, but "var a = []; a === a" is true;
+ reject(u"comparison of two empty lists"_s);
+ } else {
+ // null === null and undefined === undefined
+ m_body += invert ? u"false"_s : u"true"_s;
+ }
} else {
m_body += conversion(
m_typeResolver->boolType(), m_state.accumulatorOut().storedType(),
@@ -2462,7 +2487,7 @@ void QQmlJSCodeGenerator::generateJumpCodeWithTypeConversions(int relativeOffset
if (relativeOffset) {
auto labelIt = m_labels.find(absoluteOffset);
if (labelIt == m_labels.end())
- labelIt = m_labels.insert(absoluteOffset, u"label_%1"_s.arg(m_labels.count()));
+ labelIt = m_labels.insert(absoluteOffset, u"label_%1"_s.arg(m_labels.size()));
conversionCode += u" goto "_s + *labelIt + u";\n"_s;
}
@@ -2510,24 +2535,24 @@ QString QQmlJSCodeGenerator::conversion(const QQmlJSScope::ConstPtr &from,
const auto jsPrimitiveType = m_typeResolver->jsPrimitiveType();
const auto boolType = m_typeResolver->boolType();
- auto zeroBoolOrNumeric = [&](const QQmlJSScope::ConstPtr &to) {
+ auto zeroBoolOrInt = [&](const QQmlJSScope::ConstPtr &to) {
if (m_typeResolver->equals(to, boolType))
return u"false"_s;
if (m_typeResolver->equals(to, m_typeResolver->intType()))
return u"0"_s;
- if (m_typeResolver->equals(to, m_typeResolver->floatType()))
- return u"0.0f"_s;
- if (m_typeResolver->equals(to, m_typeResolver->realType()))
- return u"0.0"_s;
return QString();
};
if (m_typeResolver->equals(from, m_typeResolver->voidType())) {
if (to->accessSemantics() == QQmlJSScope::AccessSemantics::Reference)
return u"static_cast<"_s + to->internalName() + u" *>(nullptr)"_s;
- const QString zero = zeroBoolOrNumeric(to);
+ const QString zero = zeroBoolOrInt(to);
if (!zero.isEmpty())
return zero;
+ if (m_typeResolver->equals(to, m_typeResolver->floatType()))
+ return u"std::numeric_limits<float>::quiet_NaN()"_s;
+ if (m_typeResolver->equals(to, m_typeResolver->realType()))
+ return u"std::numeric_limits<double>::quiet_NaN()"_s;
if (m_typeResolver->equals(to, m_typeResolver->stringType()))
return QQmlJSUtils::toLiteral(u"undefined"_s);
if (m_typeResolver->equals(from, to))
@@ -2545,9 +2570,13 @@ QString QQmlJSCodeGenerator::conversion(const QQmlJSScope::ConstPtr &from,
return u"QJSPrimitiveValue(QJSPrimitiveNull())"_s;
if (m_typeResolver->equals(to, varType))
return u"QVariant::fromValue<std::nullptr_t>(nullptr)"_s;
- const QString zero = zeroBoolOrNumeric(to);
+ const QString zero = zeroBoolOrInt(to);
if (!zero.isEmpty())
return zero;
+ if (m_typeResolver->equals(to, m_typeResolver->floatType()))
+ return u"0.0f"_s;
+ if (m_typeResolver->equals(to, m_typeResolver->realType()))
+ return u"0.0"_s;
if (m_typeResolver->equals(to, m_typeResolver->stringType()))
return QQmlJSUtils::toLiteral(u"null"_s);
if (m_typeResolver->equals(from, to))
@@ -2702,21 +2731,6 @@ QString QQmlJSCodeGenerator::conversion(const QQmlJSScope::ConstPtr &from,
return QString();
}
-int QQmlJSCodeGenerator::nextJSLine(uint line) const
-{
- auto findLine = [](uint line, const QV4::CompiledData::CodeOffsetToLine &entry) {
- return entry.line > line;
- };
- const auto codeToLine
- = std::upper_bound(m_context->lineNumberMapping.constBegin(),
- m_context->lineNumberMapping.constEnd(),
- line,
- findLine);
- bool bNoNextLine = m_context->lineNumberMapping.constEnd() == codeToLine;
-
- return static_cast<int>(bNoNextLine ? -1 : codeToLine->line);
-}
-
void QQmlJSCodeGenerator::reject(const QString &thing)
{
setError(u"Cannot generate efficient code for %1"_s.arg(thing));
diff --git a/src/qmlcompiler/qqmljscodegenerator_p.h b/src/qmlcompiler/qqmljscodegenerator_p.h
index fb54ac0ad2..6fdad57831 100644
--- a/src/qmlcompiler/qqmljscodegenerator_p.h
+++ b/src/qmlcompiler/qqmljscodegenerator_p.h
@@ -33,7 +33,7 @@ public:
QQmlJSCodeGenerator(const QV4::Compiler::Context *compilerContext,
const QV4::Compiler::JSUnitGenerator *unitGenerator,
const QQmlJSTypeResolver *typeResolver,
- QQmlJSLogger *logger, const QStringList &sourceCodeLines);
+ QQmlJSLogger *logger);
~QQmlJSCodeGenerator() = default;
QQmlJSAotFunction run(const Function *function, const InstructionAnnotations *annotations,
@@ -270,17 +270,12 @@ private:
return m_typeResolver->jsGlobalObject()->property(u"Math"_s).type();
}
- int nextJSLine(uint line) const;
-
- QStringList m_sourceCodeLines;
-
// map from instruction offset to sequential label number
QHash<int, QString> m_labels;
const QV4::Compiler::Context *m_context = nullptr;
const InstructionAnnotations *m_annotations = nullptr;
- int m_lastLineNumberUsed = -1;
bool m_skipUntilNextLabel = false;
QStringList m_includes;
diff --git a/src/qmlcompiler/qqmljscompilepass_p.h b/src/qmlcompiler/qqmljscompilepass_p.h
index 40e61464f5..5c4f1c4637 100644
--- a/src/qmlcompiler/qqmljscompilepass_p.h
+++ b/src/qmlcompiler/qqmljscompilepass_p.h
@@ -166,7 +166,7 @@ protected:
int firstRegisterIndex() const
{
- return FirstArgument + m_function->argumentTypes.count();
+ return FirstArgument + m_function->argumentTypes.size();
}
bool isArgument(int registerIndex) const
@@ -184,11 +184,11 @@ protected:
State initialState(const Function *function)
{
State state;
- for (int i = 0, end = function->argumentTypes.length(); i < end; ++i) {
+ for (int i = 0, end = function->argumentTypes.size(); i < end; ++i) {
state.registers[FirstArgument + i] = function->argumentTypes.at(i);
Q_ASSERT(state.registers[FirstArgument + i].isValid());
}
- for (int i = 0, end = function->registerTypes.length(); i != end; ++i)
+ for (int i = 0, end = function->registerTypes.size(); i != end; ++i)
state.registers[firstRegisterIndex() + i] = function->registerTypes[i];
return state;
}
diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp
index 76a7ed80e2..d2e43b6f0b 100644
--- a/src/qmlcompiler/qqmljscompiler.cpp
+++ b/src/qmlcompiler/qqmljscompiler.cpp
@@ -87,7 +87,7 @@ static void annotateListElements(QmlIR::Document *document)
{
QStringList listElementNames;
- for (const QV4::CompiledData::Import *import : qAsConst(document->imports)) {
+ for (const QV4::CompiledData::Import *import : std::as_const(document->imports)) {
const QString uri = document->stringAt(import->uriIndex);
if (uri != QStringLiteral("QtQml.Models") && uri != QStringLiteral("QtQuick"))
continue;
@@ -104,7 +104,7 @@ static void annotateListElements(QmlIR::Document *document)
if (listElementNames.isEmpty())
return;
- for (QmlIR::Object *object : qAsConst(document->objects)) {
+ for (QmlIR::Object *object : std::as_const(document->objects)) {
if (!listElementNames.contains(document->stringAt(object->inheritedTypeNameIndex)))
continue;
for (QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
@@ -118,7 +118,7 @@ static void annotateListElements(QmlIR::Document *document)
static bool checkArgumentsObjectUseInSignalHandlers(const QmlIR::Document &doc,
QQmlJSCompileError *error)
{
- for (QmlIR::Object *object: qAsConst(doc.objects)) {
+ for (QmlIR::Object *object: std::as_const(doc.objects)) {
for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) {
if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
@@ -227,7 +227,7 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName,
aotCompiler->setDocument(&v4CodeGen, &irDocument);
QHash<QmlIR::Object *, QmlIR::Object *> effectiveScopes;
- for (QmlIR::Object *object: qAsConst(irDocument.objects)) {
+ for (QmlIR::Object *object: std::as_const(irDocument.objects)) {
if (object->functionsAndExpressions->count == 0 && object->bindingCount() == 0)
continue;
@@ -438,7 +438,7 @@ void wrapCall(const QQmlPrivate::AOTCompiledContext *aotContext, void *dataPtr,
{
using return_type = std::invoke_result_t<Binding, const QQmlPrivate::AOTCompiledContext *, void **>;
if constexpr (std::is_same_v<return_type, void>) {
- Q_UNUSED(dataPtr);
+ Q_UNUSED(dataPtr)
binding(aotContext, argumentsPtr);
} else {
if (dataPtr) {
@@ -453,8 +453,8 @@ void wrapCall(const QQmlPrivate::AOTCompiledContext *aotContext, void *dataPtr,
static const char *funcHeaderCode = R"(
[](const QQmlPrivate::AOTCompiledContext *aotContext, void *dataPtr, void **argumentsPtr) {
wrapCall(aotContext, dataPtr, argumentsPtr, [](const QQmlPrivate::AOTCompiledContext *aotContext, void **argumentsPtr) {
-Q_UNUSED(aotContext);
-Q_UNUSED(argumentsPtr);
+Q_UNUSED(aotContext)
+Q_UNUSED(argumentsPtr)
)";
bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFileName, const QV4::CompiledData::SaveableUnitPointer &unit, const QQmlJSAotFunctionMap &aotFunctions, QString *errorString)
@@ -509,7 +509,8 @@ bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFile
if (!writeStr(qQmlJSSymbolNamespaceForPath(inputFileName).toUtf8()))
return false;
- if (!writeStr(QByteArrayLiteral(" {\nextern const unsigned char qmlData alignas(16) [] = {\n")))
+ if (!writeStr(QByteArrayLiteral(" {\nextern const unsigned char qmlData alignas(16) [];\n"
+ "extern const unsigned char qmlData alignas(16) [] = {\n")))
return false;
unit.saveToDisk<uchar>([&writeStr](const uchar *begin, quint32 size) {
@@ -549,10 +550,12 @@ bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFile
writeStr(aotFunctions[FileScopeCodeIndex].code.toUtf8().constData());
if (aotFunctions.size() <= 1) {
// FileScopeCodeIndex is always there, but it may be the only one.
- writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = { { 0, QMetaType::fromType<void>(), {}, nullptr } };");
+ writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[];\n"
+ "extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = { { 0, QMetaType::fromType<void>(), {}, nullptr } };");
} else {
writeStr(wrapCallCode);
- writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = {\n");
+ writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[];\n"
+ "extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = {\n");
QString footer = QStringLiteral("});}\n");
@@ -621,7 +624,6 @@ void QQmlJSAotCompiler::setDocument(
m_logger->setFileName(resourcePathInfo.fileName());
m_logger->setCode(irDocument->code);
m_unitGenerator = &irDocument->jsGenerator;
- m_entireSourceCodeLines = irDocument->code.split(u'\n');
QQmlJSScope::Ptr target = QQmlJSScope::create();
QQmlJSImportVisitor visitor(target, m_importer, m_logger,
resourcePathInfo.canonicalPath() + u'/',
@@ -648,9 +650,8 @@ QQmlJS::DiagnosticMessage QQmlJSAotCompiler::diagnose(
const QString &message, QtMsgType type, const QQmlJS::SourceLocation &location) const
{
if (isStrict(m_document)
- && (type == QtWarningMsg || type == QtCriticalMsg || type == QtFatalMsg)
- && !m_logger->isCategoryIgnored(Log_Compiler)
- && m_logger->categoryLevel(Log_Compiler) == QtCriticalMsg) {
+ && (type == QtWarningMsg || type == QtCriticalMsg || type == QtFatalMsg)
+ && m_logger->isCategoryFatal(Log_Compiler)) {
qFatal("%s:%d: (strict mode) %s",
qPrintable(QFileInfo(m_resourcePath).fileName()),
location.startLine, qPrintable(message));
@@ -763,8 +764,7 @@ QQmlJSAotFunction QQmlJSAotCompiler::doCompile(
return compileError();
QQmlJSCodeGenerator codegen(
- context, m_unitGenerator, &m_typeResolver, m_logger,
- m_entireSourceCodeLines);
+ context, m_unitGenerator, &m_typeResolver, m_logger);
QQmlJSAotFunction result = codegen.run(function, &typePropagationResult, error);
return error->isValid() ? compileError() : result;
}
diff --git a/src/qmlcompiler/qqmljscompiler_p.h b/src/qmlcompiler/qqmljscompiler_p.h
index c6a60f5a94..45de4abaf1 100644
--- a/src/qmlcompiler/qqmljscompiler_p.h
+++ b/src/qmlcompiler/qqmljscompiler_p.h
@@ -75,7 +75,6 @@ protected:
const QString &message, QtMsgType type, const QQmlJS::SourceLocation &location) const;
QQmlJSTypeResolver m_typeResolver;
- QStringList m_entireSourceCodeLines;
const QString m_resourcePath;
const QStringList m_qmldirFiles;
diff --git a/src/qmlcompiler/qqmljsfunctioninitializer.cpp b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
index 56d1d25124..528b4c0602 100644
--- a/src/qmlcompiler/qqmljsfunctioninitializer.cpp
+++ b/src/qmlcompiler/qqmljsfunctioninitializer.cpp
@@ -66,7 +66,7 @@ void QQmlJSFunctionInitializer::populateSignature(
arguments = ast->formals->formals();
if (function->argumentTypes.isEmpty()) {
- for (const QQmlJS::AST::BoundName &argument : qAsConst(arguments)) {
+ for (const QQmlJS::AST::BoundName &argument : std::as_const(arguments)) {
if (argument.typeAnnotation) {
if (const auto type = m_typeResolver->typeFromAST(argument.typeAnnotation->type)) {
function->argumentTypes.append(
@@ -97,7 +97,7 @@ void QQmlJSFunctionInitializer::populateSignature(
}
}
- for (int i = QQmlJSCompilePass::FirstArgument + function->argumentTypes.length();
+ for (int i = QQmlJSCompilePass::FirstArgument + function->argumentTypes.size();
i < context->registerCountInFunction; ++i) {
function->registerTypes.append(m_typeResolver->tracked(
m_typeResolver->globalType(m_typeResolver->voidType())));
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index f0897de99f..739ad70b7e 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -81,7 +81,7 @@ void QQmlJSImporter::readQmltypes(
QQmlJS::SourceLocation()
});
- for (const QString &dependency : qAsConst(dependencyStrings)) {
+ for (const QString &dependency : std::as_const(dependencyStrings)) {
const auto blank = dependency.indexOf(u' ');
if (blank < 0) {
dependencies->append(QQmlDirParser::Import(dependency, {},
@@ -265,11 +265,11 @@ void QQmlJSImporter::importDependencies(const QQmlJSImporter::Import &import,
{
// Import the dependencies with an invalid prefix. The prefix will never be matched by actual
// QML code but the C++ types will be visible.
- for (auto const &dependency : qAsConst(import.dependencies))
+ for (auto const &dependency : std::as_const(import.dependencies))
importHelper(dependency.module, types, QString(), dependency.version, true);
bool hasOptionalImports = false;
- for (auto const &import : qAsConst(import.imports)) {
+ for (auto const &import : std::as_const(import.imports)) {
if (import.flags & QQmlDirParser::Import::Optional) {
hasOptionalImports = true;
if (!m_useOptionalImports) {
@@ -576,7 +576,7 @@ void QQmlJSImporter::importQmldirs(const QStringList &qmldirFiles)
m_seenQmldirFiles.insert(qmldirName, result);
- for (const auto &object : qAsConst(result.objects)) {
+ for (const auto &object : std::as_const(result.objects)) {
for (const auto &ex : object.exports) {
m_seenImports.insert({ex.package(), ex.version()}, qmldirName);
// We also have to handle the case that no version is provided
@@ -696,7 +696,7 @@ bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
if (modulePath.startsWith(u':')) {
if (m_mapper) {
const QString resourcePath = modulePath.mid(
- 1, modulePath.endsWith(u'/') ? modulePath.length() - 2 : -1)
+ 1, modulePath.endsWith(u'/') ? modulePath.size() - 2 : -1)
+ SlashQmldir;
const auto entry = m_mapper->entry(
QQmlJSResourceFileMapper::resourceFileFilter(resourcePath));
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 5128b0f69c..6f2a8ee265 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -283,8 +283,8 @@ void QQmlJSImportVisitor::resolveAliasesAndIds()
if (doRequeue)
requeue.enqueue(object);
- if (objects.isEmpty() && requeue.length() < lastRequeueLength) {
- lastRequeueLength = requeue.length();
+ if (objects.isEmpty() && requeue.size() < lastRequeueLength) {
+ lastRequeueLength = requeue.size();
objects.swap(requeue);
}
}
@@ -547,7 +547,7 @@ void QQmlJSImportVisitor::processDefaultProperties()
const QQmlJSMetaProperty defaultProp = parentScope->property(defaultPropertyName);
- if (it.value().length() > 1 && !defaultProp.isList()) {
+ if (it.value().size() > 1 && !defaultProp.isList()) {
m_logger->log(
QStringLiteral("Cannot assign multiple objects to a default non-list property"),
Log_Property, it.value().constFirst()->sourceLocation());
@@ -618,7 +618,7 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
// literal bindings must already be added at this point.
QSet<QPair<QQmlJSScope::Ptr, QString>> visited;
for (const PendingPropertyObjectBinding &objectBinding :
- qAsConst(m_pendingPropertyObjectBindings)) {
+ std::as_const(m_pendingPropertyObjectBindings)) {
// unique because it's per-scope and per-property
const auto uniqueBindingId = qMakePair(objectBinding.scope, objectBinding.name);
if (visited.contains(uniqueBindingId))
@@ -640,7 +640,7 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
QSet<QPair<QQmlJSScope::Ptr, QString>> foundValueSources;
for (const PendingPropertyObjectBinding &objectBinding :
- qAsConst(m_pendingPropertyObjectBindings)) {
+ std::as_const(m_pendingPropertyObjectBindings)) {
const QString propertyName = objectBinding.name;
QQmlJSScope::ConstPtr childScope = objectBinding.childScope;
@@ -780,7 +780,7 @@ void QQmlJSImportVisitor::checkRequiredProperties()
QStringList aliasExpression =
property.aliasExpression().split(u'.');
- if (aliasExpression.length() != 2)
+ if (aliasExpression.size() != 2)
continue;
if (aliasExpression[0] == scopeId
&& aliasExpression[1] == propName) {
@@ -793,8 +793,8 @@ void QQmlJSImportVisitor::checkRequiredProperties()
if (propertyUsedInRootAlias)
continue;
- const QQmlJSScope::ConstPtr propertyScope = scopesToSearch.length() > 1
- ? scopesToSearch.at(scopesToSearch.length() - 2)
+ const QQmlJSScope::ConstPtr propertyScope = scopesToSearch.size() > 1
+ ? scopesToSearch.at(scopesToSearch.size() - 2)
: QQmlJSScope::ConstPtr();
const QString propertyScopeName = !propertyScope.isNull()
@@ -971,7 +971,7 @@ void QQmlJSImportVisitor::checkSignals()
const QStringList signalParameters = signalMethod->parameterNames();
- if (pair.second.length() > signalParameters.length()) {
+ if (pair.second.size() > signalParameters.size()) {
m_logger->log(QStringLiteral("Signal handler for \"%2\" has more formal"
" parameters than the signal it handles.")
.arg(pair.first),
@@ -979,7 +979,7 @@ void QQmlJSImportVisitor::checkSignals()
continue;
}
- for (qsizetype i = 0; i < pair.second.length(); i++) {
+ for (qsizetype i = 0; i < pair.second.size(); i++) {
const QStringView handlerParameter = pair.second.at(i);
const qsizetype j = signalParameters.indexOf(handlerParameter);
if (j == i || j < 0)
@@ -1043,7 +1043,7 @@ void QQmlJSImportVisitor::breakInheritanceCycles(const QQmlJSScope::Ptr &origina
for (QQmlJSScope::ConstPtr scope = originalScope; scope;) {
if (scopes.contains(scope)) {
QString inheritenceCycle;
- for (const auto &seen : qAsConst(scopes)) {
+ for (const auto &seen : std::as_const(scopes)) {
inheritenceCycle.append(seen->baseTypeName());
inheritenceCycle.append(QLatin1String(" -> "));
}
@@ -1273,7 +1273,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::StringLiteral *sl)
bool escaped = false;
const QChar stringQuote = s[0];
- for (qsizetype i = 1; i < s.length() - 1; i++) {
+ for (qsizetype i = 1; i < s.size() - 1; i++) {
const QChar c = s[i];
if (c == u'\\') {
@@ -1287,7 +1287,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::StringLiteral *sl)
} else {
if (c == u'`')
templateString += u'\\';
- if (c == u'$' && i + 1 < s.length() - 1 && s[i + 1] == u'{')
+ if (c == u'$' && i + 1 < s.size() - 1 && s[i + 1] == u'{')
templateString += u'\\';
}
@@ -1369,10 +1369,14 @@ bool QQmlJSImportVisitor::visit(UiInlineComponent *component)
return true;
}
-void QQmlJSImportVisitor::endVisit(UiInlineComponent *)
+void QQmlJSImportVisitor::endVisit(UiInlineComponent *component)
{
m_inlineComponentName = QStringView();
- Q_ASSERT(!m_nextIsInlineComponent);
+ if (m_nextIsInlineComponent) {
+ m_logger->log(u"Inline component declaration must be followed by a typename"_s,
+ Log_Syntax, component->firstSourceLocation());
+ }
+ m_nextIsInlineComponent = false; // might have missed an inline component if file contains invalid QML
}
bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
@@ -1395,9 +1399,15 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
QString aliasExpr;
const bool isAlias = (typeName == u"alias"_s);
if (isAlias) {
+ auto tryParseAlias = [&]() {
typeName.clear(); // type name is useless for alias here, so keep it empty
+ if (!publicMember->statement) {
+ m_logger->log(QStringLiteral("Invalid alias expression – an initalizer is needed."),
+ Log_Alias, publicMember->memberType->firstSourceLocation()); // TODO: extend warning to cover until endSourceLocation
+ return;
+ }
const auto expression = cast<ExpressionStatement *>(publicMember->statement);
- auto node = expression->expression;
+ auto node = expression ? expression->expression : nullptr;
auto fex = cast<FieldMemberExpression *>(node);
while (fex) {
node = fex->base;
@@ -1412,6 +1422,8 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
"member expressions can be aliased."),
Log_Alias, expression->firstSourceLocation());
}
+ };
+ tryParseAlias();
} else {
const QString name = buildName(publicMember->memberType);
if (m_rootScopeImports.contains(name) && !m_rootScopeImports[name].scope.isNull()) {
diff --git a/src/qmlcompiler/qqmljslinter.cpp b/src/qmlcompiler/qqmljslinter.cpp
index 03eb481f5a..5c947cd321 100644
--- a/src/qmlcompiler/qqmljslinter.cpp
+++ b/src/qmlcompiler/qqmljslinter.cpp
@@ -223,9 +223,9 @@ void QQmlJSLinter::parseComments(QQmlJSLogger *logger,
if (!comment.startsWith(u" qmllint ") && !comment.startsWith(u"qmllint "))
continue;
- QStringList words = comment.split(u' ');
- if (words.constFirst().isEmpty())
- words.removeFirst();
+ QStringList words = comment.split(u' ', Qt::SkipEmptyParts);
+ if (words.size() < 2)
+ continue;
const QString command = words.at(1);
@@ -246,21 +246,23 @@ void QQmlJSLinter::parseComments(QQmlJSLogger *logger,
}
if (command == u"disable"_s) {
- const QString line = lines[loc.startLine - 1];
- const QString preComment = line.left(line.indexOf(comment) - 2);
-
- bool lineHasContent = false;
- for (qsizetype i = 0; i < preComment.size(); i++) {
- if (!preComment[i].isSpace()) {
- lineHasContent = true;
- break;
+ if (const qsizetype lineIndex = loc.startLine - 1; lineIndex < lines.size()) {
+ const QString line = lines[loc.startLine - 1];
+ const QString preComment = line.left(line.indexOf(comment) - 2);
+
+ bool lineHasContent = false;
+ for (qsizetype i = 0; i < preComment.size(); i++) {
+ if (!preComment[i].isSpace()) {
+ lineHasContent = true;
+ break;
+ }
}
- }
- if (lineHasContent)
- oneLineDisablesPerLine[loc.startLine] |= categories;
- else
- disablesPerLine[loc.startLine] |= categories;
+ if (lineHasContent)
+ oneLineDisablesPerLine[loc.startLine] |= categories;
+ else
+ disablesPerLine[loc.startLine] |= categories;
+ }
} else if (command == u"enable"_s) {
enablesPerLine[loc.startLine + 1] |= categories;
} else {
diff --git a/src/qmlcompiler/qqmljslintercodegen.cpp b/src/qmlcompiler/qqmljslintercodegen.cpp
index dfa474fc46..e362044779 100644
--- a/src/qmlcompiler/qqmljslintercodegen.cpp
+++ b/src/qmlcompiler/qqmljslintercodegen.cpp
@@ -28,7 +28,6 @@ void QQmlJSLinterCodegen::setDocument(const QmlIR::JSCodeGen *codegen,
Q_UNUSED(codegen);
m_document = document;
m_unitGenerator = &document->jsGenerator;
- m_entireSourceCodeLines = document->code.split(u'\n');
}
std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage>
diff --git a/src/qmlcompiler/qqmljsloadergenerator.cpp b/src/qmlcompiler/qqmljsloadergenerator.cpp
index 21be215bba..494ecdadd0 100644
--- a/src/qmlcompiler/qqmljsloadergenerator.cpp
+++ b/src/qmlcompiler/qqmljsloadergenerator.cpp
@@ -49,7 +49,7 @@ QString mangledIdentifier(const QString &str)
}
}
- for (int ei = str.length(); i != ei; ++i) {
+ for (int ei = str.size(); i != ei; ++i) {
auto c = str.at(i).unicode();
if ((c >= QLatin1Char('0') && c <= QLatin1Char('9'))
|| (c >= QLatin1Char('a') && c <= QLatin1Char('z'))
@@ -68,7 +68,7 @@ QString qQmlJSSymbolNamespaceForPath(const QString &relativePath)
{
QFileInfo fi(relativePath);
QString symbol = fi.path();
- if (symbol.length() == 1 && symbol.startsWith(QLatin1Char('.'))) {
+ if (symbol.size() == 1 && symbol.startsWith(QLatin1Char('.'))) {
symbol.clear();
} else {
symbol.replace(QLatin1Char('/'), QLatin1Char('_'));
@@ -105,7 +105,7 @@ bool qQmlJSGenerateLoader(const QStringList &compiledFiles, const QString &outpu
stream << "\n";
stream << "namespace QmlCacheGeneratedCode {\n";
- for (int i = 0; i < compiledFiles.count(); ++i) {
+ for (int i = 0; i < compiledFiles.size(); ++i) {
const QString compiledFile = compiledFiles.at(i);
const QString ns = qQmlJSSymbolNamespaceForPath(compiledFile);
stream << "namespace " << ns << " { \n";
@@ -131,7 +131,7 @@ bool qQmlJSGenerateLoader(const QStringList &compiledFiles, const QString &outpu
stream << "Registry::Registry() {\n";
- for (int i = 0; i < compiledFiles.count(); ++i) {
+ for (int i = 0; i < compiledFiles.size(); ++i) {
const QString qrcFile = compiledFiles.at(i);
const QString ns = qQmlJSSymbolNamespaceForPath(qrcFile);
stream << " resourcePathToCachedUnit.insert(QStringLiteral(\"" << qrcFile << "\"), &QmlCacheGeneratedCode::" << ns << "::unit);\n";
diff --git a/src/qmlcompiler/qqmljslogger.cpp b/src/qmlcompiler/qqmljslogger.cpp
index d8b1fe096f..9c22f55287 100644
--- a/src/qmlcompiler/qqmljslogger.cpp
+++ b/src/qmlcompiler/qqmljslogger.cpp
@@ -223,7 +223,7 @@ void QQmlJSLogger::printContext(const QString &overrideFileName,
int tabCount = issueLocationWithContext.beforeText().count(QLatin1Char('\t'));
int locationLength = location.length == 0 ? 1 : location.length;
- m_output.write(QString::fromLatin1(" ").repeated(issueLocationWithContext.beforeText().length()
+ m_output.write(QString::fromLatin1(" ").repeated(issueLocationWithContext.beforeText().size()
- tabCount)
+ QString::fromLatin1("\t").repeated(tabCount)
+ QString::fromLatin1("^").repeated(locationLength) + QLatin1Char('\n'));
@@ -278,9 +278,9 @@ void QQmlJSLogger::printFix(const FixSuggestion &fix)
continue;
m_output.write(u" "_s.repeated(
- issueLocationWithContext.beforeText().length() - tabCount)
+ issueLocationWithContext.beforeText().size() - tabCount)
+ u"\t"_s.repeated(tabCount)
- + u"^"_s.repeated(fixItem.replacementString.length()) + u'\n');
+ + u"^"_s.repeated(fixItem.replacementString.size()) + u'\n');
}
}
diff --git a/src/qmlcompiler/qqmljslogger_p.h b/src/qmlcompiler/qqmljslogger_p.h
index 0302201eaf..9c89fd754a 100644
--- a/src/qmlcompiler/qqmljslogger_p.h
+++ b/src/qmlcompiler/qqmljslogger_p.h
@@ -201,6 +201,16 @@ public:
m_categoryChanged[category] = true;
}
+ bool isCategoryFatal(QQmlJSLoggerCategory category) const
+ {
+ return m_categoryFatal[category];
+ }
+ void setCategoryFatal(QQmlJSLoggerCategory category, bool error)
+ {
+ m_categoryFatal[category] = error;
+ m_categoryChanged[category] = true;
+ }
+
bool wasCategoryChanged(QQmlJSLoggerCategory category) const
{
return m_categoryChanged[category];
@@ -257,6 +267,10 @@ private:
bool m_categoryIgnored[QQmlJSLoggerCategory_Last + 1] = {};
bool m_categoryChanged[QQmlJSLoggerCategory_Last + 1] = {};
+ // If true, triggers qFatal on documents with "pragma Strict"
+ // TODO: Works only for qmlCompiler category so far.
+ bool m_categoryFatal[QQmlJSLoggerCategory_Last + 1] = {};
+
QList<Message> m_infos;
QList<Message> m_warnings;
QList<Message> m_errors;
diff --git a/src/qmlcompiler/qqmljsmetatypes_p.h b/src/qmlcompiler/qqmljsmetatypes_p.h
index 75f635d5d0..e2987984fb 100644
--- a/src/qmlcompiler/qqmljsmetatypes_p.h
+++ b/src/qmlcompiler/qqmljsmetatypes_p.h
@@ -40,7 +40,7 @@ QT_BEGIN_NAMESPACE
class QQmlJSTypeResolver;
class QQmlJSScope;
-class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSMetaEnum
+class QQmlJSMetaEnum
{
QStringList m_keys;
QList<int> m_values; // empty if values unknown.
@@ -98,7 +98,7 @@ public:
}
};
-class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSMetaMethod
+class QQmlJSMetaMethod
{
public:
enum Type {
@@ -158,7 +158,7 @@ public:
}
void setParameterTypes(const QList<QSharedPointer<const QQmlJSScope>> &types)
{
- Q_ASSERT(types.length() == m_paramNames.length());
+ Q_ASSERT(types.size() == m_paramNames.size());
m_paramTypes.clear();
for (const auto &type : types)
m_paramTypes.append(type);
@@ -262,7 +262,7 @@ private:
bool m_isImplicitQmlPropertyChangeSignal = false;
};
-class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSMetaProperty
+class QQmlJSMetaProperty
{
QString m_propertyName;
QString m_typeName;
diff --git a/src/qmlcompiler/qqmljsresourcefilemapper.cpp b/src/qmlcompiler/qqmljsresourcefilemapper.cpp
index b9ae292018..4213902fb3 100644
--- a/src/qmlcompiler/qqmljsresourcefilemapper.cpp
+++ b/src/qmlcompiler/qqmljsresourcefilemapper.cpp
@@ -101,7 +101,7 @@ void doFilter(const QList<QQmlJSResourceFileMapper::Entry> &qrcPathToFileSystemP
if ((filter.flags & QQmlJSResourceFileMapper::Recurse)
// Crude. But shall we really allow slashes in QRC file names?
- || !candidate.mid(terminatedDirectory.length()).contains(u'/')) {
+ || !candidate.mid(terminatedDirectory.size()).contains(u'/')) {
if (handler(*it))
return;
}
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index 3e0cff0e52..03d47203ce 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -267,6 +267,9 @@ bool QQmlJSScope::causesImplicitComponentWrapping(const QQmlJSMetaProperty &prop
Either because it has been implicitly wrapped, e.g. due to an assignment to
a Component property, or because it is the first (and only) child of a
Component.
+ For visitors: This method should only be called after implicit components
+ are detected, that is, after QQmlJSImportVisitor::endVisit(UiProgram *)
+ was called.
*/
bool QQmlJSScope::isComponentRootElement() const {
if (m_flags.testFlag(WrappedInImplicitComponent))
@@ -339,7 +342,7 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
const QString outerTypeName = name.left(colonColon);
const auto outerType = contextualTypes.constFind(outerTypeName);
if (outerType != contextualTypes.constEnd()) {
- for (const auto &innerType : qAsConst(outerType->scope->m_childScopes)) {
+ for (const auto &innerType : std::as_const(outerType->scope->m_childScopes)) {
if (innerType->m_internalName == name) {
if (usedTypes != nullptr)
usedTypes->insert(name);
@@ -394,10 +397,10 @@ QTypeRevision QQmlJSScope::resolveType(
const auto paramTypeNames = it->parameterTypeNames();
QList<QSharedPointer<const QQmlJSScope>> paramTypes = it->parameterTypes();
- if (paramTypes.length() < paramTypeNames.length())
- paramTypes.resize(paramTypeNames.length());
+ if (paramTypes.size() < paramTypeNames.size())
+ paramTypes.resize(paramTypeNames.size());
- for (int i = 0, length = paramTypes.length(); i < length; ++i) {
+ for (int i = 0, length = paramTypes.size(); i < length; ++i) {
auto &paramType = paramTypes[i];
const auto paramTypeName = paramTypeNames[i];
if (!paramType && !paramTypeName.isEmpty()) {
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 46aee20d90..6047d0c1d9 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -278,10 +278,30 @@ public:
{
using namespace Qt::StringLiterals;
- QString suffix;
- if (m_semantics == AccessSemantics::Reference)
- suffix = u" *"_s;
- return m_internalName + suffix;
+ switch (m_semantics) {
+ case AccessSemantics::Reference:
+ return m_internalName + " *"_L1;
+ case AccessSemantics::Value:
+ case AccessSemantics::Sequence:
+ break;
+ case AccessSemantics::None:
+ // If we got a namespace, it might still be a regular type, exposed as namespace.
+ // We may need to travel the inheritance chain all the way up to QObject to
+ // figure this out, since all other types may be exposed the same way.
+ for (QQmlJSScope::ConstPtr base = baseType(); base; base = base->baseType()) {
+ switch (base->accessSemantics()) {
+ case AccessSemantics::Reference:
+ return m_internalName + " *"_L1;
+ case AccessSemantics::Value:
+ case AccessSemantics::Sequence:
+ return m_internalName;
+ case AccessSemantics::None:
+ break;
+ }
+ }
+ break;
+ }
+ return m_internalName;
}
// This returns a more user readable version of internalName / baseTypeName
diff --git a/src/qmlcompiler/qqmljsshadowcheck.cpp b/src/qmlcompiler/qqmljsshadowcheck.cpp
index 719eeaef31..086b778263 100644
--- a/src/qmlcompiler/qqmljsshadowcheck.cpp
+++ b/src/qmlcompiler/qqmljsshadowcheck.cpp
@@ -36,11 +36,14 @@ void QQmlJSShadowCheck::run(
m_function = function;
m_error = error;
m_state = initialState(function);
- decode(m_function->code.constData(), static_cast<uint>(m_function->code.length()));
+ decode(m_function->code.constData(), static_cast<uint>(m_function->code.size()));
}
void QQmlJSShadowCheck::generate_LoadProperty(int nameIndex)
{
+ if (!m_state.readsRegister(Accumulator))
+ return; // enum lookup cannot be shadowed.
+
auto accumulatorIn = m_state.registers.find(Accumulator);
if (accumulatorIn != m_state.registers.end())
checkShadowing(accumulatorIn.value(), m_jsUnitGenerator->stringForIndex(nameIndex));
@@ -48,6 +51,9 @@ void QQmlJSShadowCheck::generate_LoadProperty(int nameIndex)
void QQmlJSShadowCheck::generate_GetLookup(int index)
{
+ if (!m_state.readsRegister(Accumulator))
+ return; // enum lookup cannot be shadowed.
+
auto accumulatorIn = m_state.registers.find(Accumulator);
if (accumulatorIn != m_state.registers.end())
checkShadowing(accumulatorIn.value(), m_jsUnitGenerator->lookupName(index));
diff --git a/src/qmlcompiler/qqmljsstreamwriter.cpp b/src/qmlcompiler/qqmljsstreamwriter.cpp
index 093d15dbd4..e435b8df92 100644
--- a/src/qmlcompiler/qqmljsstreamwriter.cpp
+++ b/src/qmlcompiler/qqmljsstreamwriter.cpp
@@ -161,7 +161,7 @@ void QQmlJSStreamWriter::flushPotentialLinesWithNewlines()
{
if (m_maybeOneline)
m_stream->write("\n");
- for (const QByteArray &line : qAsConst(m_pendingLines)) {
+ for (const QByteArray &line : std::as_const(m_pendingLines)) {
writeIndent();
m_stream->write(line);
m_stream->write("\n");
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index bab06d1035..9469380bba 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -50,7 +50,7 @@ QQmlJSCompilePass::InstructionAnnotations QQmlJSTypePropagator::run(
m_state.State::operator=(initialState(m_function));
reset();
- decode(m_function->code.constData(), static_cast<uint>(m_function->code.length()));
+ decode(m_function->code.constData(), static_cast<uint>(m_function->code.size()));
// If we have found unresolved backwards jumps, we need to start over with a fresh state.
// Mind that m_jumpOriginRegisterStateByTargetInstructionOffset is retained in that case.
@@ -287,20 +287,20 @@ void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name, bool isM
if (isMethod) {
if (isCallingProperty(m_function->qmlScope, name))
return;
- } else if (isMissingPropertyType(m_function->qmlScope, name)) {
+ } else if (propertyResolution(m_function->qmlScope, name) != PropertyMissing) {
return;
}
std::optional<FixSuggestion> suggestion;
auto childScopes = m_function->qmlScope->childScopes();
- for (qsizetype i = 0; i < m_function->qmlScope->childScopes().length(); i++) {
+ for (qsizetype i = 0; i < m_function->qmlScope->childScopes().size(); i++) {
auto &scope = childScopes[i];
if (location.offset > scope->sourceLocation().offset) {
- if (i + 1 < childScopes.length()
+ if (i + 1 < childScopes.size()
&& childScopes.at(i + 1)->sourceLocation().offset < location.offset)
continue;
- if (scope->childScopes().length() == 0)
+ if (scope->childScopes().size() == 0)
continue;
const auto jsId = scope->childScopes().first()->findJSIdentifier(name);
@@ -481,18 +481,20 @@ bool QQmlJSTypePropagator::isRestricted(const QString &propertyName) const
}
// Only to be called once a lookup has already failed
-bool QQmlJSTypePropagator::isMissingPropertyType(QQmlJSScope::ConstPtr scope,
- const QString &propertyName) const
+QQmlJSTypePropagator::PropertyResolution QQmlJSTypePropagator::propertyResolution(
+ QQmlJSScope::ConstPtr scope, const QString &propertyName) const
{
auto property = scope->property(propertyName);
if (!property.isValid())
- return false;
+ return PropertyMissing;
QString errorType;
if (property.type().isNull())
errorType = u"found"_s;
else if (!property.type()->isFullyResolved())
errorType = u"fully resolved"_s;
+ else
+ return PropertyFullyResolved;
Q_ASSERT(!errorType.isEmpty());
@@ -501,7 +503,7 @@ bool QQmlJSTypePropagator::isMissingPropertyType(QQmlJSScope::ConstPtr scope,
.arg(property.typeName(), propertyName, errorType),
Log_Type, getCurrentSourceLocation());
- return true;
+ return PropertyTypeUnresolved;
}
bool QQmlJSTypePropagator::isCallingProperty(QQmlJSScope::ConstPtr scope, const QString &name) const
@@ -664,6 +666,10 @@ void QQmlJSTypePropagator::generate_StoreElement(int base, int index)
addReadAccumulator(jsValue);
addReadRegister(base, jsValue);
addReadRegister(index, jsValue);
+
+ // Writing to a JS array can have side effects all over the place since it's
+ // passed by reference.
+ m_state.setHasSideEffects(true);
return;
}
@@ -777,7 +783,7 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName)
auto baseType = m_typeResolver->containedType(m_state.accumulatorIn());
// Warn separately when a property is only not found because of a missing type
- if (isMissingPropertyType(baseType, propertyName))
+ if (propertyResolution(baseType, propertyName) != PropertyMissing)
return;
std::optional<FixSuggestion> fixSuggestion;
@@ -808,7 +814,7 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName)
return;
}
- if (m_state.accumulatorOut().isMethod() && m_state.accumulatorOut().method().length() != 1) {
+ if (m_state.accumulatorOut().isMethod() && m_state.accumulatorOut().method().size() != 1) {
setError(u"Cannot determine overloaded method on loadProperty"_s);
return;
}
@@ -1026,8 +1032,9 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar
if (m_passManager != nullptr) {
// TODO: Should there be an analyzeCall() in the future? (w. corresponding onCall in Pass)
- m_passManager->analyzeRead(m_typeResolver->containedType(m_state.accumulatorIn()),
- propertyName, m_function->qmlScope, getCurrentSourceLocation());
+ m_passManager->analyzeRead(
+ m_typeResolver->containedType(callBase),
+ propertyName, m_function->qmlScope, getCurrentSourceLocation());
}
addReadRegister(base, callBase);
@@ -1159,8 +1166,8 @@ void QQmlJSTypePropagator::propagateCall(const QList<QQmlJSMetaMethod> &methods,
const QQmlJSMetaMethod match = bestMatchForCall(methods, argc, argv, &errors);
if (!match.isValid()) {
- Q_ASSERT(errors.length() == methods.length());
- if (methods.length() == 1)
+ Q_ASSERT(errors.size() == methods.size());
+ if (methods.size() == 1)
setError(errors.first());
else
setError(u"No matching override found. Candidates:\n"_s + errors.join(u'\n'));
@@ -1180,7 +1187,7 @@ void QQmlJSTypePropagator::propagateCall(const QList<QQmlJSMetaMethod> &methods,
m_state.setHasSideEffects(true);
const auto types = match.parameterTypes();
for (int i = 0; i < argc; ++i) {
- if (i < types.length()) {
+ if (i < types.size()) {
const QQmlJSScope::ConstPtr type = match.isJavaScriptFunction()
? m_typeResolver->jsValueType()
: QQmlJSScope::ConstPtr(types.at(i));
@@ -2156,12 +2163,12 @@ QString QQmlJSTypePropagator::registerName(int registerIndex) const
if (registerIndex == Accumulator)
return u"accumulator"_s;
if (registerIndex >= FirstArgument
- && registerIndex < FirstArgument + m_function->argumentTypes.count()) {
+ && registerIndex < FirstArgument + m_function->argumentTypes.size()) {
return u"argument %1"_s.arg(registerIndex - FirstArgument);
}
return u"temporary register %1"_s.arg(
- registerIndex - FirstArgument - m_function->argumentTypes.count());
+ registerIndex - FirstArgument - m_function->argumentTypes.size());
}
QQmlJSRegisterContent QQmlJSTypePropagator::checkedInputRegister(int reg)
diff --git a/src/qmlcompiler/qqmljstypepropagator_p.h b/src/qmlcompiler/qqmljstypepropagator_p.h
index 30967413b9..06fc2c9793 100644
--- a/src/qmlcompiler/qqmljstypepropagator_p.h
+++ b/src/qmlcompiler/qqmljstypepropagator_p.h
@@ -191,7 +191,14 @@ private:
void checkDeprecated(QQmlJSScope::ConstPtr scope, const QString &name, bool isMethod) const;
bool isRestricted(const QString &propertyName) const;
bool isCallingProperty(QQmlJSScope::ConstPtr scope, const QString &name) const;
- bool isMissingPropertyType(QQmlJSScope::ConstPtr scope, const QString &type) const;
+
+ enum PropertyResolution {
+ PropertyMissing,
+ PropertyTypeUnresolved,
+ PropertyFullyResolved
+ };
+
+ PropertyResolution propertyResolution(QQmlJSScope::ConstPtr scope, const QString &type) const;
QQmlJS::SourceLocation getCurrentSourceLocation() const;
QQmlJS::SourceLocation getCurrentBindingSourceLocation() const;
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index 046a79ce01..eeb5f605f0 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -38,6 +38,10 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
m_varType = builtinTypes[u"QVariant"_s].scope;
m_jsValueType = builtinTypes[u"QJSValue"_s].scope;
+ QQmlJSScope::Ptr emptyType = QQmlJSScope::create();
+ emptyType->setAccessSemantics(QQmlJSScope::AccessSemantics::None);
+ m_emptyType = emptyType;
+
QQmlJSScope::Ptr emptyListType = QQmlJSScope::create();
emptyListType->setInternalName(u"void*"_s);
emptyListType->setAccessSemantics(QQmlJSScope::AccessSemantics::Sequence);
@@ -70,7 +74,7 @@ QQmlJSTypeResolver::QQmlJSTypeResolver(QQmlJSImporter *importer)
m_jsGlobalObject = importer->jsGlobalObject();
auto numberMethods = m_jsGlobalObject->methods(u"Number"_s);
- Q_ASSERT(numberMethods.length() == 1);
+ Q_ASSERT(numberMethods.size() == 1);
m_numberPrototype = numberMethods[0].returnType()->baseType();
Q_ASSERT(m_numberPrototype);
Q_ASSERT(m_numberPrototype->internalName() == u"NumberPrototype"_s);
@@ -169,7 +173,10 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::typeForConst(QV4::ReturnedValue rv) co
return realType();
if (value.isNull())
- return jsPrimitiveType();
+ return nullType();
+
+ if (value.isEmpty())
+ return emptyType();
return {};
}
@@ -396,6 +403,64 @@ QQmlJSRegisterContent QQmlJSTypeResolver::transformed(
return {};
}
+QQmlJSRegisterContent QQmlJSTypeResolver::referenceTypeForName(
+ const QString &name, const QQmlJSScope::ConstPtr &scopeType,
+ bool hasObjectModulePrefix) const
+{
+ QQmlJSScope::ConstPtr type = typeForName(name);
+ if (!type)
+ return QQmlJSRegisterContent();
+
+ if (type->isSingleton())
+ return QQmlJSRegisterContent::create(storedType(type), type,
+ QQmlJSRegisterContent::Singleton, scopeType);
+
+ if (type->isScript())
+ return QQmlJSRegisterContent::create(storedType(type), type,
+ QQmlJSRegisterContent::Script, scopeType);
+
+ if (const auto attached = type->attachedType()) {
+ if (!genericType(attached)) {
+ m_logger->log(u"Cannot resolve generic base of attached %1"_s.arg(
+ attached->internalName()),
+ Log_Compiler, attached->sourceLocation());
+ return {};
+ } else if (type->accessSemantics() != QQmlJSScope::AccessSemantics::Reference) {
+ m_logger->log(u"Cannot retrieve attached object for non-reference type %1"_s.arg(
+ type->internalName()),
+ Log_Compiler, type->sourceLocation());
+ return {};
+ } else {
+ // We don't know yet whether we need the attached or the plain object. In direct
+ // mode, we will figure this out using the scope type and access any enums of the
+ // plain type directly. In indirect mode, we can use enum lookups.
+ return QQmlJSRegisterContent::create(
+ storedType(attached), attached,
+ hasObjectModulePrefix
+ ? QQmlJSRegisterContent::ObjectAttached
+ : QQmlJSRegisterContent::ScopeAttached, type);
+ }
+ }
+
+ switch (type->accessSemantics()) {
+ case QQmlJSScope::AccessSemantics::None:
+ case QQmlJSScope::AccessSemantics::Reference:
+ // A plain reference to a non-singleton, non-attached type.
+ // We may still need the plain type reference for enum lookups,
+ // Store it as QMetaObject.
+ // This only works with namespaces and object types.
+ return QQmlJSRegisterContent::create(metaObjectType(), metaObjectType(),
+ QQmlJSRegisterContent::MetaType, type);
+ case QQmlJSScope::AccessSemantics::Sequence:
+ case QQmlJSScope::AccessSemantics::Value:
+ // This is not actually a type reference. You cannot get the metaobject
+ // of a value type in QML and sequences don't even have metaobjects.
+ break;
+ }
+
+ return QQmlJSRegisterContent();
+}
+
QQmlJSRegisterContent QQmlJSTypeResolver::original(const QQmlJSRegisterContent &type) const
{
return transformed(type, &QQmlJSTypeResolver::originalType);
@@ -643,7 +708,8 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPt
return m_metaObjectType;
if (type->accessSemantics() == QQmlJSScope::AccessSemantics::Reference) {
- for (auto base = type; base; base = base->baseType()) {
+ QString unresolvedBaseTypeName;
+ for (auto base = type; base;) {
// QObject and QQmlComponent are the two required base types.
// Any QML type system has to define those, or use the ones from builtins.
// As QQmlComponent is derived from QObject, we can restrict ourselves to the latter.
@@ -655,10 +721,19 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPt
&& base->internalName() == u"QQmlComponent"_s) {
return base;
}
+
+ if (auto baseBase = base->baseType()) {
+ base = baseBase;
+ } else {
+ unresolvedBaseTypeName = base->baseTypeName();
+ break;
+ }
}
- m_logger->log(u"Object type %1 is not derived from QObject or QQmlComponent"_s.arg(
- type->internalName()),
+ m_logger->log(u"Object type %1 is not derived from QObject or QQmlComponent. "
+ "You may need to fully qualify all names in C++ so that moc can see them. "
+ "You may also need to add qt_extract_metatypes(<target containing %2>)."_s
+ .arg(type->internalName(), unresolvedBaseTypeName),
Log_Compiler, type->sourceLocation());
// Reference types that are not QObject or QQmlComponent are likely JavaScript objects.
@@ -685,6 +760,7 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPt
return type;
if (const QQmlJSScope::ConstPtr valueType = type->valueType())
return listType(genericType(valueType), UseQObjectList);
+ return m_variantListType;
}
return m_varType;
@@ -802,51 +878,9 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSScope::ConstPtr
}
}
- if (QQmlJSScope::ConstPtr type = typeForName(name)) {
- if (type->isSingleton())
- return QQmlJSRegisterContent::create(storedType(type), type,
- QQmlJSRegisterContent::Singleton);
-
- if (type->isScript())
- return QQmlJSRegisterContent::create(storedType(type), type,
- QQmlJSRegisterContent::Script);
-
- if (const auto attached = type->attachedType()) {
- if (!genericType(attached)) {
- m_logger->log(u"Cannot resolve generic base of attached %1"_s.arg(
- attached->internalName()),
- Log_Compiler, attached->sourceLocation());
- return {};
- } else if (type->accessSemantics() != QQmlJSScope::AccessSemantics::Reference) {
- m_logger->log(u"Cannot retrieve attached object for non-reference type %1"_s.arg(
- type->internalName()),
- Log_Compiler, type->sourceLocation());
- return {};
- } else {
- // We don't know yet whether we need the attached or the plain object. In direct
- // mode, we will figure this out using the scope type and access any enums of the
- // plain type directly. In indirect mode, we can use enum lookups.
- return QQmlJSRegisterContent::create(storedType(attached), attached,
- QQmlJSRegisterContent::ScopeAttached, type);
- }
- }
-
- switch (type->accessSemantics()) {
- case QQmlJSScope::AccessSemantics::None:
- case QQmlJSScope::AccessSemantics::Reference:
- // A plain reference to a non-singleton, non-attached type.
- // We may still need the plain type reference for enum lookups,
- // Store it as QMetaObject.
- // This only works with namespaces and object types.
- return QQmlJSRegisterContent::create(metaObjectType(), metaObjectType(),
- QQmlJSRegisterContent::MetaType, type);
- case QQmlJSScope::AccessSemantics::Sequence:
- case QQmlJSScope::AccessSemantics::Value:
- // This is not actually a type reference. You cannot get the metaobject
- // of a value type in QML and sequences don't even have metaobjects.
- break;
- }
- }
+ QQmlJSRegisterContent result = referenceTypeForName(name);
+ if (result.isValid())
+ return result;
if (m_jsGlobalObject->hasProperty(name)) {
return QQmlJSRegisterContent::create(jsValueType(), m_jsGlobalObject->property(name),
@@ -987,6 +1021,10 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSScope::ConstPtr
{
QQmlJSRegisterContent result;
+ // If we got a plain type reference we have to check the enums of the _scope_.
+ if (equals(type, metaObjectType()))
+ return {};
+
if (equals(type, jsValueType())) {
QQmlJSMetaProperty prop;
prop.setPropertyName(name);
@@ -1134,34 +1172,9 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSRegisterContent
return {};
}
- if (QQmlJSScope::ConstPtr result = typeForName(name)) {
- QQmlJSScope::ConstPtr attached = result->attachedType();
- if (attached && genericType(attached)) {
- return QQmlJSRegisterContent::create(
- storedType(attached), attached,
- type.variant() == QQmlJSRegisterContent::ObjectModulePrefix
- ? QQmlJSRegisterContent::ObjectAttached
- : QQmlJSRegisterContent::ScopeAttached,
- result);
- }
-
- if (result->isSingleton()) {
- return QQmlJSRegisterContent::create(
- storedType(result), result,
- QQmlJSRegisterContent::Singleton, type.scopeType());
- }
-
- if (result->isScript()) {
- return QQmlJSRegisterContent::create(
- storedType(result), result,
- QQmlJSRegisterContent::Script, type.scopeType());
- }
-
- return QQmlJSRegisterContent::create(metaObjectType(), metaObjectType(),
- QQmlJSRegisterContent::MetaType, result);
- }
-
- return {};
+ return referenceTypeForName(
+ name, type.scopeType(),
+ type.variant() == QQmlJSRegisterContent::ObjectModulePrefix);
}
if (type.isConversion()) {
const auto result = memberType(type.conversionResult(), name);
@@ -1243,7 +1256,7 @@ bool QQmlJSTypeResolver::registerContains(const QQmlJSRegisterContent &reg,
: equals(type, prop.type());
}
if (reg.isEnumeration())
- return equals(type, intType());
+ return equals(type, reg.enumeration().type());
if (reg.isMethod())
return equals(type, jsValueType());
return false;
diff --git a/src/qmlcompiler/qqmljstyperesolver_p.h b/src/qmlcompiler/qqmljstyperesolver_p.h
index e05f5b3757..a56a85bbc6 100644
--- a/src/qmlcompiler/qqmljstyperesolver_p.h
+++ b/src/qmlcompiler/qqmljstyperesolver_p.h
@@ -39,6 +39,7 @@ public:
void init(QQmlJSImportVisitor *visitor, QQmlJS::AST::Node *program);
QQmlJSScope::ConstPtr voidType() const { return m_voidType; }
+ QQmlJSScope::ConstPtr emptyType() const { return m_emptyType; }
QQmlJSScope::ConstPtr emptyListType() const { return m_emptyListType; }
QQmlJSScope::ConstPtr nullType() const { return m_nullType; }
QQmlJSScope::ConstPtr realType() const { return m_realType; }
@@ -167,8 +168,14 @@ protected:
const QQmlJSRegisterContent &origin,
QQmlJSScope::ConstPtr (QQmlJSTypeResolver::*op)(const QQmlJSScope::ConstPtr &) const) const;
+ QQmlJSRegisterContent referenceTypeForName(
+ const QString &name,
+ const QQmlJSScope::ConstPtr &scopeType = QQmlJSScope::ConstPtr(),
+ bool hasObjectModuelPrefix = false) const;
+
QQmlJSScope::ConstPtr m_voidType;
QQmlJSScope::ConstPtr m_emptyListType;
+ QQmlJSScope::ConstPtr m_emptyType;
QQmlJSScope::ConstPtr m_nullType;
QQmlJSScope::ConstPtr m_numberPrototype;
QQmlJSScope::ConstPtr m_realType;
diff --git a/src/qmlcompiler/qqmljsutils.cpp b/src/qmlcompiler/qqmljsutils.cpp
index c07c0b6845..8ef11444d7 100644
--- a/src/qmlcompiler/qqmljsutils.cpp
+++ b/src/qmlcompiler/qqmljsutils.cpp
@@ -25,17 +25,23 @@ resolveAlias(ScopeForId scopeForId, const QQmlJSMetaProperty &property,
QQmlJSUtils::ResolvedAlias result {};
result.owner = owner;
- for (QQmlJSMetaProperty nextProperty = property; nextProperty.isAlias();) {
-
- // this is a special (seemingly useless) section which is necessary when
- // we have an alias pointing to an alias. this way we avoid a check
- // whether a property is an alias at the very end of the loop body
+ // TODO: one could optimize the generated alias code for aliases pointing to aliases
+ // e.g., if idA.myAlias -> idB.myAlias2 -> idC.myProp, then one could directly generate
+ // idA.myProp as pointing to idC.myProp.
+ // This gets complicated when idB.myAlias is in a different Component than where the
+ // idA.myAlias is defined: scopeForId currently only contains the ids of the current
+ // component and alias resolution on the ids of a different component fails then.
+ if (QQmlJSMetaProperty nextProperty = property; nextProperty.isAlias()) {
QQmlJSScope::ConstPtr resultOwner = result.owner;
result = QQmlJSUtils::ResolvedAlias {};
visitor.reset();
auto aliasExprBits = nextProperty.aliasExpression().split(u'.');
+ // do not crash on invalid aliasexprbits when accessing aliasExprBits[0]
+ if (aliasExprBits.size() < 1)
+ return {};
+
// resolve id first:
resultOwner = scopeForId(aliasExprBits[0], resultOwner);
if (!resultOwner)
@@ -46,10 +52,8 @@ resolveAlias(ScopeForId scopeForId, const QQmlJSMetaProperty &property,
aliasExprBits.removeFirst(); // Note: for simplicity, remove the <id>
result.owner = resultOwner;
result.kind = QQmlJSUtils::AliasTarget_Object;
- // reset the property to avoid endless loop when aliasExprBits is empty
- nextProperty = QQmlJSMetaProperty {};
- for (const QString &bit : qAsConst(aliasExprBits)) {
+ for (const QString &bit : std::as_const(aliasExprBits)) {
nextProperty = resultOwner->property(bit);
if (!nextProperty.isValid())
return {};
@@ -96,7 +100,7 @@ std::optional<FixSuggestion> QQmlJSUtils::didYouMean(const QString &userInput,
QQmlJS::SourceLocation location)
{
QString shortestDistanceWord;
- int shortestDistance = userInput.length();
+ int shortestDistance = userInput.size();
// Most of the time the candidates are keys() from QHash, which means that
// running this function in the seemingly same setup might yield different
@@ -114,14 +118,14 @@ std::optional<FixSuggestion> QQmlJSUtils::didYouMean(const QString &userInput,
* Roughly based on
* https://en.wikipedia.org/wiki/Levenshtein_distance#Iterative_with_two_matrix_rows.
*/
- QList<int> v0(candidate.length() + 1);
- QList<int> v1(candidate.length() + 1);
+ QList<int> v0(candidate.size() + 1);
+ QList<int> v1(candidate.size() + 1);
std::iota(v0.begin(), v0.end(), 0);
- for (qsizetype i = 0; i < userInput.length(); i++) {
+ for (qsizetype i = 0; i < userInput.size(); i++) {
v1[0] = i + 1;
- for (qsizetype j = 0; j < candidate.length(); j++) {
+ for (qsizetype j = 0; j < candidate.size(); j++) {
int deletionCost = v0[j + 1] + 1;
int insertionCost = v1[j] + 1;
int substitutionCost = userInput[i] == candidate[j] ? v0[j] : v0[j] + 1;
@@ -130,7 +134,7 @@ std::optional<FixSuggestion> QQmlJSUtils::didYouMean(const QString &userInput,
std::swap(v0, v1);
}
- int distance = v0[candidate.length()];
+ int distance = v0[candidate.size()];
if (distance < shortestDistance) {
shortestDistanceWord = candidate;
shortestDistance = distance;
@@ -138,7 +142,7 @@ std::optional<FixSuggestion> QQmlJSUtils::didYouMean(const QString &userInput,
}
if (shortestDistance
- < std::min(std::max(userInput.length() / 2, qsizetype(3)), userInput.length())) {
+ < std::min(std::max(userInput.size() / 2, qsizetype(3)), userInput.size())) {
return FixSuggestion { { FixSuggestion::Fix {
u"Did you mean \"%1\"?"_s.arg(shortestDistanceWord), location,
shortestDistanceWord } } };
diff --git a/src/qmlcompiler/qqmljsutils_p.h b/src/qmlcompiler/qqmljsutils_p.h
index 8a1ee9c287..040e996cd4 100644
--- a/src/qmlcompiler/qqmljsutils_p.h
+++ b/src/qmlcompiler/qqmljsutils_p.h
@@ -104,7 +104,7 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSUtils
{
if (handlerName.startsWith(u"on") && handlerName.size() > 2) {
QString signal = handlerName.mid(2).toString();
- for (int i = 0; i < signal.length(); ++i) {
+ for (int i = 0; i < signal.size(); ++i) {
QChar &ch = signal[i];
if (ch.isLower())
return {};