summaryrefslogtreecommitdiffstats
path: root/src/declarative/qml
diff options
context:
space:
mode:
authormae <qt-info@nokia.com>2010-04-26 08:59:46 (GMT)
committermae <qt-info@nokia.com>2010-04-26 09:02:02 (GMT)
commitc3be50311d8d343609aa4f108e4e713d367e2907 (patch)
tree335ed095fa8e82729b3c6c4da0a7a38456fd0bb0 /src/declarative/qml
parentb64226e7b8cb1c9922b5419b27e0888c3215aae3 (diff)
downloadQt-c3be50311d8d343609aa4f108e4e713d367e2907.zip
Qt-c3be50311d8d343609aa4f108e4e713d367e2907.tar.gz
Qt-c3be50311d8d343609aa4f108e4e713d367e2907.tar.bz2
Improved error messages for type resolving, new debug option
The patch improves the error messages when type resolving fails and introduces a new debug utility QML_CHECK_TYPES. If the environment variable is defined, type shadowing will be reported as error. Reviewed-by: Warwick Allison
Diffstat (limited to 'src/declarative/qml')
-rw-r--r--src/declarative/qml/qdeclarativecompositetypemanager.cpp6
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp179
-rw-r--r--src/declarative/qml/qdeclarativeengine_p.h3
3 files changed, 133 insertions, 55 deletions
diff --git a/src/declarative/qml/qdeclarativecompositetypemanager.cpp b/src/declarative/qml/qdeclarativecompositetypemanager.cpp
index adeb7a5..0eb7e1b 100644
--- a/src/declarative/qml/qdeclarativecompositetypemanager.cpp
+++ b/src/declarative/qml/qdeclarativecompositetypemanager.cpp
@@ -617,7 +617,8 @@ int QDeclarativeCompositeTypeManager::resolveTypes(QDeclarativeCompositeTypeData
int majorVersion;
int minorVersion;
QDeclarativeEnginePrivate::ImportedNamespace *typeNamespace = 0;
- if (!QDeclarativeEnginePrivate::get(engine)->resolveType(unit->imports, typeName, &ref.type, &url, &majorVersion, &minorVersion, &typeNamespace)
+ QString errorString;
+ if (!QDeclarativeEnginePrivate::get(engine)->resolveType(unit->imports, typeName, &ref.type, &url, &majorVersion, &minorVersion, &typeNamespace, &errorString)
|| typeNamespace)
{
// Known to not be a type:
@@ -630,7 +631,8 @@ int QDeclarativeCompositeTypeManager::resolveTypes(QDeclarativeCompositeTypeData
if (typeNamespace)
error.setDescription(tr("Namespace %1 cannot be used as a type").arg(userTypeName));
else
- error.setDescription(tr("%1 is not a type").arg(userTypeName));
+ error.setDescription(tr("%1 %2").arg(userTypeName).arg(errorString));
+
if (!parserRef->refObjects.isEmpty()) {
QDeclarativeParser::Object *obj = parserRef->refObjects.first();
error.setLine(obj->location.start.line);
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index 8eae120..f31cf53 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -112,6 +112,7 @@ Q_DECLARE_METATYPE(QDeclarativeProperty)
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE)
+DEFINE_BOOL_CONFIG_OPTION(qmlCheckTypes, QML_CHECK_TYPES)
/*!
\qmlclass QtObject QObject
@@ -1543,55 +1544,65 @@ struct QDeclarativeEnginePrivate::ImportedNamespace {
QList<bool> isLibrary;
QList<QDeclarativeDirComponents> qmlDirComponents;
- bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return, QUrl* url_return,
- QUrl *base = 0)
+
+ bool find_helper(int i, const QByteArray& type, int *vmajor, int *vminor,
+ QDeclarativeType** type_return, QUrl* url_return,
+ QUrl *base = 0, bool *typeRecursionDetected = 0)
{
- for (int i=0; i<urls.count(); ++i) {
- int vmaj = majversions.at(i);
- int vmin = minversions.at(i);
-
- QByteArray qt = uris.at(i).toUtf8();
- qt += '/';
- qt += type;
-
- QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin);
- if (t) {
- if (vmajor) *vmajor = vmaj;
- if (vminor) *vminor = vmin;
- if (type_return)
- *type_return = t;
- return true;
- }
+ int vmaj = majversions.at(i);
+ int vmin = minversions.at(i);
+
+ QByteArray qt = uris.at(i).toUtf8();
+ qt += '/';
+ qt += type;
+
+ QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin);
+ if (t) {
+ if (vmajor) *vmajor = vmaj;
+ if (vminor) *vminor = vmin;
+ if (type_return)
+ *type_return = t;
+ return true;
+ }
- QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
- QDeclarativeDirComponents qmldircomponents = qmlDirComponents.at(i);
-
- bool typeWasDeclaredInQmldir = false;
- if (!qmldircomponents.isEmpty()) {
- const QString typeName = QString::fromUtf8(type);
- foreach (const QDeclarativeDirParser::Component &c, qmldircomponents) {
- if (c.typeName == typeName) {
- typeWasDeclaredInQmldir = true;
-
- // importing version -1 means import ALL versions
- if ((vmaj == -1) || (c.majorVersion < vmaj || (c.majorVersion == vmaj && vmin >= c.minorVersion))) {
- QUrl candidate = url.resolved(QUrl(c.fileName));
- if (c.internal && base) {
- if (base->resolved(QUrl(c.fileName)) != candidate)
- continue; // failed attempt to access an internal type
- }
- if (url_return)
- *url_return = candidate;
- return true;
+ QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
+ QDeclarativeDirComponents qmldircomponents = qmlDirComponents.at(i);
+
+ bool typeWasDeclaredInQmldir = false;
+ if (!qmldircomponents.isEmpty()) {
+ const QString typeName = QString::fromUtf8(type);
+ foreach (const QDeclarativeDirParser::Component &c, qmldircomponents) {
+ if (c.typeName == typeName) {
+ typeWasDeclaredInQmldir = true;
+
+ // importing version -1 means import ALL versions
+ if ((vmaj == -1) || (c.majorVersion < vmaj || (c.majorVersion == vmaj && vmin >= c.minorVersion))) {
+ QUrl candidate = url.resolved(QUrl(c.fileName));
+ if (c.internal && base) {
+ if (base->resolved(QUrl(c.fileName)) != candidate)
+ continue; // failed attempt to access an internal type
}
+ if (base && *base == candidate) {
+ if (typeRecursionDetected)
+ *typeRecursionDetected = true;
+ continue; // no recursion
+ }
+ if (url_return)
+ *url_return = candidate;
+ return true;
}
}
}
+ }
- if (!typeWasDeclaredInQmldir && !isLibrary.at(i)) {
- // XXX search non-files too! (eg. zip files, see QT-524)
- QFileInfo f(toLocalFileOrQrc(url));
- if (f.exists()) {
+ if (!typeWasDeclaredInQmldir && !isLibrary.at(i)) {
+ // XXX search non-files too! (eg. zip files, see QT-524)
+ QFileInfo f(toLocalFileOrQrc(url));
+ if (f.exists()) {
+ if (base && *base == url) { // no recursion
+ if (typeRecursionDetected)
+ *typeRecursionDetected = true;
+ } else {
if (url_return)
*url_return = url;
return true;
@@ -1600,6 +1611,63 @@ struct QDeclarativeEnginePrivate::ImportedNamespace {
}
return false;
}
+
+ bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
+ QUrl* url_return, QUrl *base = 0, QString *errorString = 0)
+ {
+ bool typeRecursionDetected = false;
+ for (int i=0; i<urls.count(); ++i) {
+ if (find_helper(i, type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) {
+ if (qmlCheckTypes()) {
+ // check for type clashes
+ for (int j = i+1; j<urls.count(); ++j) {
+ if (find_helper(j, type, vmajor, vminor, 0, 0, base)) {
+ if (errorString) {
+ QString u1 = urls.at(i);
+ QString u2 = urls.at(j);
+ if (base) {
+ QString b = base->toString();
+ int slash = b.lastIndexOf(QLatin1Char('/'));
+ if (slash >= 0) {
+ b = b.left(slash+1);
+ QString l = b.left(slash);
+ if (u1.startsWith(b))
+ u1 = u1.mid(b.count());
+ else if (u1 == l)
+ u1 = QDeclarativeEngine::tr("local directory");
+ if (u2.startsWith(b))
+ u2 = u2.mid(b.count());
+ else if (u2 == l)
+ u2 = QDeclarativeEngine::tr("local directory");
+ }
+ }
+
+ if (u1 != u2)
+ *errorString
+ = QDeclarativeEngine::tr("is ambiguous. Found in %1 and in %2")
+ .arg(u1).arg(u2);
+ else
+ *errorString
+ = QDeclarativeEngine::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
+ .arg(u1)
+ .arg(majversions.at(i)).arg(minversions.at(i))
+ .arg(majversions.at(j)).arg(minversions.at(j));
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+ if (errorString) {
+ if (typeRecursionDetected)
+ *errorString = QDeclarativeEngine::tr("is instantiated recursively");
+ else
+ *errorString = QDeclarativeEngine::tr("is not a type");
+ }
+ return false;
+ }
};
static bool greaterThan(const QString &s1, const QString &s2)
@@ -1809,30 +1877,37 @@ public:
return true;
}
- bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return, QUrl* url_return)
+ bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
+ QUrl* url_return, QString *errorString)
{
QDeclarativeEnginePrivate::ImportedNamespace *s = 0;
int slash = type.indexOf('/');
if (slash >= 0) {
- s = set.value(QString::fromUtf8(type.left(slash)));
- if (!s)
- return false; // qualifier must be a namespace
+ QString namespaceName = QString::fromUtf8(type.left(slash));
+ s = set.value(namespaceName);
+ if (!s) {
+ if (errorString)
+ *errorString = QDeclarativeEngine::tr("- %1 is not a namespace").arg(namespaceName);
+ return false;
+ }
int nslash = type.indexOf('/',slash+1);
- if (nslash > 0)
- return false; // only single qualification allowed
+ if (nslash > 0) {
+ if (errorString)
+ *errorString = QDeclarativeEngine::tr("- nested namespaces not allowed");
+ return false;
+ }
} else {
s = &unqualifiedset;
}
QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
if (s) {
- if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base))
+ if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errorString))
return true;
if (s->urls.count() == 1 && !s->isLibrary[0] && url_return && s != &unqualifiedset) {
// qualified, and only 1 url
*url_return = QUrl(s->urls[0]+QLatin1Char('/')).resolved(QUrl(QString::fromUtf8(unqualifiedtype) + QLatin1String(".qml")));
return true;
}
-
}
return false;
@@ -2329,7 +2404,7 @@ bool QDeclarativeEnginePrivate::addToImport(Imports* imports, const QDeclarative
\sa addToImport()
*/
-bool QDeclarativeEnginePrivate::resolveType(const Imports& imports, const QByteArray& type, QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin, ImportedNamespace** ns_return) const
+bool QDeclarativeEnginePrivate::resolveType(const Imports& imports, const QByteArray& type, QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin, ImportedNamespace** ns_return, QString *errorString) const
{
ImportedNamespace* ns = imports.d->findNamespace(QString::fromUtf8(type));
if (ns) {
@@ -2338,7 +2413,7 @@ bool QDeclarativeEnginePrivate::resolveType(const Imports& imports, const QByteA
return true;
}
if (type_return || url_return) {
- if (imports.d->find(type,vmaj,vmin,type_return,url_return)) {
+ if (imports.d->find(type,vmaj,vmin,type_return,url_return, errorString)) {
if (qmlImportTrace()) {
if (type_return && *type_return && url_return && !url_return->isEmpty())
qDebug() << "QDeclarativeEngine::resolveType" << type << '=' << (*type_return)->typeName() << *url_return;
diff --git a/src/declarative/qml/qdeclarativeengine_p.h b/src/declarative/qml/qdeclarativeengine_p.h
index f6b9bcb..743275e 100644
--- a/src/declarative/qml/qdeclarativeengine_p.h
+++ b/src/declarative/qml/qdeclarativeengine_p.h
@@ -290,7 +290,8 @@ public:
bool resolveType(const Imports&, const QByteArray& type,
QDeclarativeType** type_return, QUrl* url_return,
int *version_major, int *version_minor,
- ImportedNamespace** ns_return) const;
+ ImportedNamespace** ns_return,
+ QString *errorString = 0) const;
void resolveTypeInNamespace(ImportedNamespace*, const QByteArray& type,
QDeclarativeType** type_return, QUrl* url_return,
int *version_major, int *version_minor ) const;