patch-KDevelopPath=canonical.diff

File Metadata

Author
rjvbb
Created
Sep 22 2017, 7:56 PM

patch-KDevelopPath=canonical.diff

diff --git a/kdevplatform/util/path.cpp b/kdevplatform/util/path.cpp
index edcbfbe9adbcdb80b8b51759099aad0cc9e7deb1..b71b6f186f3ba514c2ebae480a06e4fa73a77b6d 100644
--- a/kdevplatform/util/path.cpp
+++ b/kdevplatform/util/path.cpp
@@ -23,6 +23,7 @@
#include "path.h"
#include <QStringList>
+#include <QFileInfo>
#include <QDebug>
#include <language/util/kdevhash.h>
@@ -397,13 +398,36 @@ static QVarLengthArray<QString, 16> splitPath(const QString &source)
return list;
}
+//
+static QString toCanonicalPath(const QString &path)
+{
+ const QFileInfo info(path);
+ if (info.exists()) {
+ if (info.isDir()) {
+ // the simple case: just resolve all symlinks in the entire path
+ return info.canonicalFilePath();
+ } else {
+ // resolve the symlinks in the path to the file, and reappend the filename
+ return QFileInfo(info.absolutePath()).canonicalFilePath() + QStringLiteral("/") + info.fileName();
+ }
+ }
+ // don't attempt anything on non-existing files, it will fail
+ return path;
+}
+
void Path::addPath(const QString& path)
{
if (path.isEmpty()) {
return;
}
- const auto& newData = splitPath(path);
+ // convert local paths to canonical if not adding it to an existing path
+ const bool convertToCanonical = m_data.isEmpty() && path.startsWith(QLatin1Char('/'));
+ // Use QFileInfo::canonicalPath() to resolve any symlinks on the path, but not the
+ // final element (filename). This returns an empty string when path doesn't exist
+ // so we need to check the result.
+ const QString canonicalPath = convertToCanonical ? toCanonicalPath(path) : QString();
+ const auto& newData = splitPath(canonicalPath.isEmpty() ? path : canonicalPath);
if (newData.isEmpty()) {
if (m_data.size() == (isRemote() ? 1 : 0)) {
// this represents the root path, we just turned an invalid path into it
@@ -421,6 +445,17 @@ void Path::addPath(const QString& path)
std::copy(it, newData.end(), std::back_inserter(m_data));
cleanPath(&m_data, isRemote());
+ // convert the concatenated result to canonical if local
+ // can surely be done in a more efficient manner
+ if (canonicalPath.isEmpty() && isLocalFile()) {
+ Path temp;
+ // using the default Path ctor is the fastest and easiest way
+ // to call ourselves with a fresh temporary m_data instance
+ temp.addPath(toCanonicalPath(generatePathOrUrl(true, true, m_data)));
+ if (!temp.m_data.isEmpty()) {
+ m_data = temp.m_data;
+ }
+ }
}
Path Path::parent() const