summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2020-11-12 16:11:50 +0100
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2020-11-15 18:30:16 +0100
commit784a290c4b08e84d895a62dada5420a3b47dde48 (patch)
tree3a327a2d2bf0447704b68b4989398646e90cd476
parent1869615fc959c70a334e666ebf95ff595a3d6e67 (diff)
QFileInfo: mark constructors as explicit
These look like leftovers (API flaws). Construction of QFileInfo from QString (or similar) should be not implicit, as QFileInfo construction is expensive (might hit the file system), and this may have users overlook APIs (for instance build a QFileInfo out of QDirIterator::next(), instead of using ::fileInfo(); using QDir::entryList instead of entryInfoList; etc.). Leave an opt-out mechanism to ease porting. Fix a handful of usages around qtbase, with at least a couple of them likely to be actual "sloppy" code. [ChangeLog][Potentially Source-Incompatible Changes][QFileInfo] Most QFileInfo constructors are now explicit. The QT_IMPLICIT_QFILEINFO_CONSTRUCTION macro is provided to keep old code working. Change-Id: Ic580e6316e67edbc840aa0c60d98c7aaabaf1af6 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--qmake/generators/metamakefile.cpp4
-rw-r--r--src/corelib/global/qlibraryinfo.cpp4
-rw-r--r--src/corelib/io/qfileinfo.cpp57
-rw-r--r--src/corelib/io/qfileinfo.h19
-rw-r--r--src/gui/itemmodels/qfileinfogatherer.cpp3
-rw-r--r--src/plugins/platforms/xcb/qxcbsessionmanager.cpp2
-rw-r--r--src/testlib/qtestcase.cpp2
-rw-r--r--src/tools/androiddeployqt/main.cpp5
-rw-r--r--tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp2
-rw-r--r--tests/auto/widgets/itemviews/qfileiconprovider/tst_qfileiconprovider.cpp2
10 files changed, 83 insertions, 17 deletions
diff --git a/qmake/generators/metamakefile.cpp b/qmake/generators/metamakefile.cpp
index 8d1eb1d886..8ba941c213 100644
--- a/qmake/generators/metamakefile.cpp
+++ b/qmake/generators/metamakefile.cpp
@@ -335,11 +335,11 @@ SubdirsMetaMakefileGenerator::init()
QFileInfo subdir(subdirs.at(i).toQString());
const ProKey fkey(subdirs.at(i) + ".file");
if (!project->isEmpty(fkey)) {
- subdir = project->first(fkey).toQString();
+ subdir = QFileInfo(project->first(fkey).toQString());
} else {
const ProKey skey(subdirs.at(i) + ".subdir");
if (!project->isEmpty(skey))
- subdir = project->first(skey).toQString();
+ subdir = QFileInfo(project->first(skey).toQString());
}
QString sub_name;
if(subdir.isDir())
diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp
index 990c4269e3..4cd940a7a3 100644
--- a/src/corelib/global/qlibraryinfo.cpp
+++ b/src/corelib/global/qlibraryinfo.cpp
@@ -597,8 +597,8 @@ QString qmake_abslocation();
static QString getPrefixFromHostBinDir(const char *hostBinDirToPrefixPath)
{
- const QFileInfo qmfi = QFileInfo(qmake_abslocation()).canonicalFilePath();
- return QDir::cleanPath(qmfi.absolutePath() + QLatin1Char('/')
+ const QString canonicalQMakePath = QFileInfo(qmake_abslocation()).canonicalPath();
+ return QDir::cleanPath(canonicalQMakePath + QLatin1Char('/')
+ QLatin1String(hostBinDirToPrefixPath));
}
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 8b80141a32..4b81467687 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -1621,5 +1621,62 @@ QDebug operator<<(QDebug dbg, const QFileInfo &fi)
Returns symLinkTarget() as a \c{std::filesystem::path}.
\sa symLinkTarget()
*/
+/*!
+ \macro QT_IMPLICIT_QFILEINFO_CONSTRUCTION
+ \since 6.0
+ \relates QFileInfo
+
+ Defining this macro makes most QFileInfo constructors implicit
+ instead of explicit. Since construction of QFileInfo objects is
+ expensive, one should avoid accidentally creating them, especially
+ if cheaper alternatives exist. For instance:
+
+ \badcode
+
+ QDirIterator it(dir);
+ while (it.hasNext()) {
+ // Implicit conversion from QString (returned by it.next()):
+ // may create unnecessary data strucutres and cause additional
+ // accesses to the file system. Unless this macro is defined,
+ // this line does not compile.
+
+ QFileInfo fi = it.next();
+
+ ~~~
+ }
+
+ \endcode
+
+ Instead, use the right API:
+
+ \code
+
+ QDirIterator it(dir);
+ while (it.hasNext()) {
+ it.next();
+
+ // Extract the QFileInfo from the iterator directly:
+ QFileInfo fi = it.fileInfo();
+
+ ~~~
+ }
+
+ \endcode
+
+ Construction from QString, QFile, and so on is always possible by
+ using direct initialization instead of copy initialization:
+
+ \code
+
+ QFileInfo fi1 = some_string; // Does not compile unless this macro is defined
+ QFileInfo fi2(some_string); // OK
+ QFileInfo fi3{some_string}; // Possibly better, avoids the risk of the Most Vexing Parse
+ auto fi4 = QFileInfo(some_string); // OK
+
+ \endcode
+
+ This macro is provided for compatibility reason. Its usage is not
+ recommended in new code.
+*/
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h
index 344c16abf8..90be1c2540 100644
--- a/src/corelib/io/qfileinfo.h
+++ b/src/corelib/io/qfileinfo.h
@@ -59,23 +59,32 @@ class Q_CORE_EXPORT QFileInfo
public:
explicit QFileInfo(QFileInfoPrivate *d);
+#ifdef QT_IMPLICIT_QFILEINFO_CONSTRUCTION
+#define QFILEINFO_MAYBE_EXPLICIT Q_IMPLICIT
+#else
+#define QFILEINFO_MAYBE_EXPLICIT explicit
+#endif
+
QFileInfo();
- QFileInfo(const QString &file);
- QFileInfo(const QFileDevice &file);
- QFileInfo(const QDir &dir, const QString &file);
+ QFILEINFO_MAYBE_EXPLICIT QFileInfo(const QString &file);
+ QFILEINFO_MAYBE_EXPLICIT QFileInfo(const QFileDevice &file);
+ QFILEINFO_MAYBE_EXPLICIT QFileInfo(const QDir &dir, const QString &file);
QFileInfo(const QFileInfo &fileinfo);
#ifdef Q_CLANG_QDOC
QFileInfo(const std::filesystem::path &file);
QFileInfo(const QDir &dir, const std::filesystem::path &file);
#elif QT_CONFIG(cxx17_filesystem)
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
- QFileInfo(const T &file) : QFileInfo(QtPrivate::fromFilesystemPath(file)) { }
+ QFILEINFO_MAYBE_EXPLICIT QFileInfo(const T &file) : QFileInfo(QtPrivate::fromFilesystemPath(file)) { }
template<typename T, QtPrivate::ForceFilesystemPath<T> = 0>
- QFileInfo(const QDir &dir, const T &file) : QFileInfo(dir, QtPrivate::fromFilesystemPath(file))
+ QFILEINFO_MAYBE_EXPLICIT QFileInfo(const QDir &dir, const T &file) : QFileInfo(dir, QtPrivate::fromFilesystemPath(file))
{
}
#endif // QT_CONFIG(cxx17_filesystem)
+
+#undef QFILEINFO_MAYBE_EXPLICIT
+
~QFileInfo();
QFileInfo &operator=(const QFileInfo &fileinfo);
diff --git a/src/gui/itemmodels/qfileinfogatherer.cpp b/src/gui/itemmodels/qfileinfogatherer.cpp
index 417c3d7e42..bd368e945c 100644
--- a/src/gui/itemmodels/qfileinfogatherer.cpp
+++ b/src/gui/itemmodels/qfileinfogatherer.cpp
@@ -350,8 +350,7 @@ QExtendedInformation QFileInfoGatherer::getInfo(const QFileInfo &fileInfo) const
#ifdef Q_OS_WIN
if (m_resolveSymlinks && info.isSymLink(/* ignoreNtfsSymLinks = */ true)) {
- QFileInfo resolvedInfo(fileInfo.symLinkTarget());
- resolvedInfo = resolvedInfo.canonicalFilePath();
+ QFileInfo resolvedInfo(QFileInfo(fileInfo.symLinkTarget()).canonicalFilePath());
if (resolvedInfo.exists()) {
emit nameResolved(fileInfo.filePath(), resolvedInfo.fileName());
}
diff --git a/src/plugins/platforms/xcb/qxcbsessionmanager.cpp b/src/plugins/platforms/xcb/qxcbsessionmanager.cpp
index e9697f505b..002fccba07 100644
--- a/src/plugins/platforms/xcb/qxcbsessionmanager.cpp
+++ b/src/plugins/platforms/xcb/qxcbsessionmanager.cpp
@@ -230,7 +230,7 @@ static void sm_performSaveYourself(QXcbSessionManager *sm)
restart << argument0 << QLatin1String("-session")
<< sm->sessionId() + QLatin1Char('_') + sm->sessionKey();
- QFileInfo fi = QCoreApplication::applicationFilePath();
+ QFileInfo fi(QCoreApplication::applicationFilePath());
if (qAppName().compare(fi.fileName(), Qt::CaseInsensitive) != 0)
restart << QLatin1String("-name") << qAppName();
sm->setRestartCommand(restart);
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index 992149ff20..7bca8de1b6 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -2211,7 +2211,7 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co
// 3. relative to test source.
if (found.isEmpty() && qstrncmp(file, ":/", 2) != 0) {
// srcdir is the directory containing the calling source file.
- QFileInfo srcdir = QFileInfo(QFile::decodeName(file)).path();
+ QFileInfo srcdir(QFileInfo(QFile::decodeName(file)).path());
// If the srcdir is relative, that means it is relative to the current working
// directory of the compiler at compile time, which should be passed in as `builddir'.
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index 0e04f97a33..1b29fe7381 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -1561,8 +1561,9 @@ QList<QtDependency> findFilesRecursively(const Options &options, const QFileInfo
const QStringList entries = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
for (const QString &entry : entries) {
- QString s = info.absoluteFilePath() + QLatin1Char('/') + entry;
- ret += findFilesRecursively(options, s, rootPath);
+ ret += findFilesRecursively(options,
+ QFileInfo(info.absoluteFilePath() + QChar(u'/') + entry),
+ rootPath);
}
return ret;
diff --git a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
index b0b076310d..2d7c1b295a 100644
--- a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
+++ b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp
@@ -364,7 +364,7 @@ static inline QFileInfo findSh()
const QStringList rawPaths = QString::fromLocal8Bit(pEnv.constData()).split(pathSep, Qt::SkipEmptyParts);
foreach (const QString &path, rawPaths) {
if (QFile::exists(path + sh))
- return path + sh;
+ return QFileInfo(path + sh);
}
return QFileInfo();
}
diff --git a/tests/auto/widgets/itemviews/qfileiconprovider/tst_qfileiconprovider.cpp b/tests/auto/widgets/itemviews/qfileiconprovider/tst_qfileiconprovider.cpp
index 4824973576..9e9625854e 100644
--- a/tests/auto/widgets/itemviews/qfileiconprovider/tst_qfileiconprovider.cpp
+++ b/tests/auto/widgets/itemviews/qfileiconprovider/tst_qfileiconprovider.cpp
@@ -126,7 +126,7 @@ void tst_QFileIconProvider::type()
static QIcon getIcon()
{
QFileIconProvider fip;
- return fip.icon(QDir::currentPath());
+ return fip.icon(QFileInfo(QDir::currentPath()));
}
void tst_QFileIconProvider::taskQTBUG_46755_QFileIconEngine_crash()