From a2f40fce2a1cf3c19a13fa27eea08192493ab76e Mon Sep 17 00:00:00 2001
From: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Date: Fri, 10 Jul 2009 13:37:02 +0200
Subject: [PATCH] implement proper vpath handling for qt4 projects

this also removes the bogus special casing of various
filename-containing variables inside the pro parser.
---
 .../qt4projectmanager/profilereader.cpp       |  48 ------
 src/plugins/qt4projectmanager/profilereader.h |   5 -
 src/plugins/qt4projectmanager/qt4nodes.cpp    |  33 +++-
 src/shared/proparser/profileevaluator.cpp     | 158 ++++++------------
 src/shared/proparser/profileevaluator.h       |   5 +-
 5 files changed, 81 insertions(+), 168 deletions(-)

diff --git a/src/plugins/qt4projectmanager/profilereader.cpp b/src/plugins/qt4projectmanager/profilereader.cpp
index e8f8e833994..5bef6ecd6ce 100644
--- a/src/plugins/qt4projectmanager/profilereader.cpp
+++ b/src/plugins/qt4projectmanager/profilereader.cpp
@@ -107,54 +107,6 @@ QString ProFileReader::value(const QString &variable) const
 }
 
 
-// Construct QFileInfo from path value and base directory
-// Truncate trailing slashs and make absolute
-static inline QFileInfo infoFromPath(QString path,
-                              const QString &baseDirectory)
-{
-    if (path.size() > 1 && path.endsWith(QLatin1Char('/')))
-        path.truncate(path.size() - 1);
-    QFileInfo info(path);
-    if (info.isAbsolute())
-        return info;
-    return QFileInfo(baseDirectory, path);
-}
-
-/*!
-  Returns a list of absolute paths
-  */
-QStringList ProFileReader::absolutePathValues(const QString &variable,
-                                              const QString &baseDirectory,
-                                              PathValuesMode mode,
-                                              const ProFile *pro) const
-{
-    QStringList rawList;
-    if (!pro)
-        rawList = values(variable);
-    else
-        rawList = values(variable, pro);
-
-    if (rawList.isEmpty())
-        return QStringList();
-
-    // Normalize list of paths, kill trailing slashes,
-    // remove duplicates while maintaining order
-    const QChar slash = QLatin1Char('/');
-    QStringList result;
-    const QStringList::const_iterator rcend = rawList.constEnd();
-    for (QStringList::const_iterator it = rawList.constBegin(); it != rcend; ++it) {
-        const QFileInfo info = infoFromPath(*it, baseDirectory);
-        if (mode == AllPaths || info.exists()) {
-            if (mode != ExistingFilePaths || info.isFile()) {
-                const QString absPath = info.absoluteFilePath();
-                if (!result.contains(absPath))
-                    result.push_back(absPath);
-            }
-        }
-    }
-    return result;
-}
-
 void ProFileReader::fileMessage(const QString &message)
 {
     Q_UNUSED(message);
diff --git a/src/plugins/qt4projectmanager/profilereader.h b/src/plugins/qt4projectmanager/profilereader.h
index cded457cdf3..74a8745ac60 100644
--- a/src/plugins/qt4projectmanager/profilereader.h
+++ b/src/plugins/qt4projectmanager/profilereader.h
@@ -53,11 +53,6 @@ public:
 
     QString value(const QString &variable) const;
 
-    enum PathValuesMode { AllPaths, ExistingPaths, ExistingFilePaths };
-    QStringList absolutePathValues(const QString &variable,
-                                   const QString &baseDirectory,
-                                   PathValuesMode mode,
-                                   const ProFile *pro = 0) const;
     ProFile *proFileFor(const QString &name);
 signals:
     void errorFound(const QString &error);
diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp
index f1556eb5ff0..e8b3de82965 100644
--- a/src/plugins/qt4projectmanager/qt4nodes.cpp
+++ b/src/plugins/qt4projectmanager/qt4nodes.cpp
@@ -132,14 +132,30 @@ void Qt4PriFileNode::update(ProFile *includeFile, ProFileReader *reader)
                                   << ProjectExplorer::ResourceType
                                   << ProjectExplorer::UnknownFileType);
 
+    const QString &projectDir = m_qt4ProFileNode->m_projectDir;
+
+    QStringList baseVPaths;
+    baseVPaths += reader->absolutePathValues("VPATH", projectDir);
+    baseVPaths << projectDir; // QMAKE_ABSOLUTE_SOURCE_PATH
+    baseVPaths += reader->absolutePathValues("DEPENDPATH", projectDir);
+    baseVPaths.removeDuplicates();
+
     // update files
-    const QDir projectDir = QFileInfo(m_projectFilePath).dir();
     foreach (FileType type, fileTypes) {
         const QStringList qmakeVariables = varNames(type);
 
         QStringList newFilePaths;
-        foreach (const QString &qmakeVariable, qmakeVariables)
-            newFilePaths += reader->absolutePathValues(qmakeVariable, projectDir.path(), ProFileReader::ExistingFilePaths, includeFile);
+        foreach (const QString &qmakeVariable, qmakeVariables) {
+            QStringList vPaths;
+            if (type == ProjectExplorer::SourceType)
+                vPaths = reader->absolutePathValues("VPATH_" + qmakeVariable, projectDir);
+            vPaths += baseVPaths;
+            if (type == ProjectExplorer::HeaderType)
+                vPaths += reader->absolutePathValues("INCLUDEPATH", projectDir);
+            vPaths.removeDuplicates();
+            newFilePaths += reader->absoluteFileValues(qmakeVariable, projectDir, vPaths, includeFile);
+        }
+        newFilePaths.removeDuplicates();
 
         QList<FileNode*> existingFileNodes;
         foreach (FileNode *fileNode, fileNodes()) {
@@ -896,16 +912,16 @@ Qt4ProFileNode *Qt4ProFileNode::createSubProFileNode(const QString &path)
 QStringList Qt4ProFileNode::uiDirPaths(ProFileReader *reader) const
 {
     QStringList candidates = reader->absolutePathValues(QLatin1String("UI_DIR"),
-                                                        buildDir(),
-                                                        ProFileReader::ExistingPaths);
+                                                        buildDir());
+    candidates.removeDuplicates();
     return candidates;
 }
 
 QStringList Qt4ProFileNode::mocDirPaths(ProFileReader *reader) const
 {
     QStringList candidates = reader->absolutePathValues(QLatin1String("MOC_DIR"),
-                                                        buildDir(),
-                                                        ProFileReader::ExistingPaths);
+                                                        buildDir());
+    candidates.removeDuplicates();
     return candidates;
 }
 
@@ -913,8 +929,7 @@ QStringList Qt4ProFileNode::includePaths(ProFileReader *reader) const
 {
     QStringList paths;
     paths = reader->absolutePathValues(QLatin1String("INCLUDEPATH"),
-                                       m_projectDir,
-                                       ProFileReader::ExistingPaths);
+                                       m_projectDir);
     paths << uiDirPaths(reader) << mocDirPaths(reader);
     paths.removeDuplicates();
     return paths;
diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp
index 295e094a9ce..27e3932cb95 100644
--- a/src/shared/proparser/profileevaluator.cpp
+++ b/src/shared/proparser/profileevaluator.cpp
@@ -182,9 +182,6 @@ public:
     QString propertyValue(const QString &val) const;
 
     bool isActiveConfig(const QString &config, bool regex = false);
-    QStringList expandPattern(const QString &pattern);
-    void expandPatternHelper(const QString &relName, const QString &absName,
-        QStringList &sources_out);
     QStringList expandVariableReferences(const QString &value);
     void doVariableReplace(QString *str);
     QStringList evaluateExpandFunction(const QString &function, const QString &arguments);
@@ -844,32 +841,6 @@ void ProFileEvaluator::Private::visitProValue(ProValue *value)
     m_prevLineNo = m_lineNo;
     m_prevProFile = currentProFile();
 
-    // The following two blocks fix bug 180128 by making all "interesting"
-    // file name absolute in each .pro file, not just the top most one
-    if (varName == QLatin1String("SOURCES")
-            || varName == QLatin1String("OBJECTIVE_SOURCES")
-            || varName == QLatin1String("HEADERS")
-            || varName == QLatin1String("INTERFACES")
-            || varName == QLatin1String("FORMS")
-            || varName == QLatin1String("FORMS3")
-            || varName == QLatin1String("RESOURCES")
-            || varName == QLatin1String("LEXSOURCES")
-            || varName == QLatin1String("YACCSOURCES")){
-        // matches only existent files, expand certain(?) patterns
-        QStringList vv;
-        for (int i = v.count(); --i >= 0; )
-            vv << expandPattern(v[i]);
-        v = vv;
-    }
-
-    if (varName == QLatin1String("TRANSLATIONS")) {
-        // also matches non-existent files, but does not expand pattern
-        QString dir = QFileInfo(currentFileName()).absolutePath();
-        dir += QLatin1Char('/');
-        for (int i = v.count(); --i >= 0; )
-            v[i] = QFileInfo(dir, v[i]).absoluteFilePath();
-    }
-
     switch (m_variableOperator) {
         case ProVariable::SetOperator:          // =
             if (!m_cumulative) {
@@ -2495,82 +2466,6 @@ bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName)
     return ok;
 }
 
-void ProFileEvaluator::Private::expandPatternHelper(const QString &relName, const QString &absName,
-        QStringList &sources_out)
-{
-    const QStringList vpaths = values(QLatin1String("VPATH"))
-        + values(QLatin1String("QMAKE_ABSOLUTE_SOURCE_PATH"))
-        + values(QLatin1String("DEPENDPATH"))
-        + values(QLatin1String("VPATH_SOURCES"));
-
-    QFileInfo fi(absName);
-    bool found = fi.exists();
-    // Search in all vpaths
-    if (!found) {
-        foreach (const QString &vpath, vpaths) {
-            fi.setFile(vpath + QDir::separator() + relName);
-            if (fi.exists()) {
-                found = true;
-                break;
-            }
-        }
-    }
-
-    if (found) {
-        sources_out += fi.absoluteFilePath(); // Not resolving symlinks
-    } else {
-        QString val = relName;
-        QString dir;
-        QString wildcard = val;
-        QString real_dir;
-        if (wildcard.lastIndexOf(QLatin1Char('/')) != -1) {
-            dir = wildcard.left(wildcard.lastIndexOf(QLatin1Char('/')) + 1);
-            real_dir = dir;
-            wildcard = wildcard.right(wildcard.length() - dir.length());
-        }
-
-        if (real_dir.isEmpty() || QFileInfo(real_dir).exists()) {
-            QStringList files = QDir(real_dir).entryList(QStringList(wildcard));
-            if (files.isEmpty()) {
-                q->logMessage(format("Failure to find %1").arg(val));
-            } else {
-                QString a;
-                for (int i = files.count() - 1; i >= 0; --i) {
-                    if (files[i] == QLatin1String(".") || files[i] == QLatin1String(".."))
-                        continue;
-                    a = dir + files[i];
-                    sources_out += a;
-                }
-            }
-        } else {
-            q->logMessage(format("Cannot match %1/%2, as %3 does not exist.")
-                .arg(real_dir).arg(wildcard).arg(real_dir));
-        }
-    }
-}
-
-
-/*
- * Lookup of files are done in this order:
- *  1. look in pwd
- *  2. look in vpaths
- *  3. expand wild card files relative from the profiles folder
- **/
-
-// FIXME: This code supports something that I'd consider a flaw in .pro file syntax
-// which is not even documented. So arguably this can be ditched completely...
-QStringList ProFileEvaluator::Private::expandPattern(const QString& pattern)
-{
-    if (!currentProFile())
-        return QStringList();
-
-    QStringList sources_out;
-    const QString absName = QDir::cleanPath(QDir::current().absoluteFilePath(pattern));
-
-    expandPatternHelper(pattern, absName, sources_out);
-    return sources_out;
-}
-
 QString ProFileEvaluator::Private::format(const char *fmt) const
 {
     ProFile *pro = currentProFile();
@@ -2621,6 +2516,59 @@ QStringList ProFileEvaluator::values(const QString &variableName, const ProFile
     return fixEnvVariables(d->values(variableName, pro));
 }
 
+QStringList ProFileEvaluator::absolutePathValues(
+        const QString &variable, const QString &baseDirectory) const
+{
+    QStringList result;
+    foreach (const QString &el, values(variable)) {
+        const QFileInfo info = QFileInfo(baseDirectory, el);
+        if (info.isDir())
+            result << QDir::cleanPath(info.absoluteFilePath());
+    }
+    return result;
+}
+
+QStringList ProFileEvaluator::absoluteFileValues(
+        const QString &variable, const QString &baseDirectory, const QStringList &searchDirs,
+        const ProFile *pro) const
+{
+    QStringList result;
+    foreach (const QString &el, pro ? values(variable, pro) : values(variable)) {
+        QFileInfo info(el);
+        if (info.isAbsolute()) {
+            if (info.exists()) {
+                result << QDir::cleanPath(el);
+                goto next;
+            }
+        } else {
+            foreach (const QString &dir, searchDirs) {
+                QFileInfo info(dir, el);
+                if (info.isFile()) {
+                    result << QDir::cleanPath(info.filePath());
+                    goto next;
+                }
+            }
+            if (baseDirectory.isEmpty())
+                goto next;
+            info = QFileInfo(baseDirectory, el);
+        }
+        {
+            QFileInfo baseInfo(info.absolutePath());
+            if (baseInfo.exists()) {
+                QString wildcard = info.fileName();
+                if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) {
+                    QDir theDir(QDir::cleanPath(baseInfo.filePath()));
+                    foreach (const QString &fn, theDir.entryList(QStringList(wildcard)))
+                        if (fn != QLatin1String(".") && fn != QLatin1String(".."))
+                            result << theDir.absoluteFilePath(fn);
+                } // else if (acceptMissing)
+            }
+        }
+      next: ;
+    }
+    return result;
+}
+
 ProFileEvaluator::TemplateType ProFileEvaluator::templateType()
 {
     QStringList templ = values(QLatin1String("TEMPLATE"));
diff --git a/src/shared/proparser/profileevaluator.h b/src/shared/proparser/profileevaluator.h
index 9bd88c0c03d..55a5c53776c 100644
--- a/src/shared/proparser/profileevaluator.h
+++ b/src/shared/proparser/profileevaluator.h
@@ -40,7 +40,6 @@
 
 QT_BEGIN_NAMESPACE
 
-class ProFile;
 class ProFileEvaluator;
 
 void evaluateProFile(const ProFileEvaluator &visitor, QHash<QByteArray, QStringList> *varMap);
@@ -76,6 +75,10 @@ public:
     void addProperties(const QHash<QString, QString> &properties);
     QStringList values(const QString &variableName) const;
     QStringList values(const QString &variableName, const ProFile *pro) const;
+    QStringList absolutePathValues(const QString &variable, const QString &baseDirectory) const;
+    QStringList absoluteFileValues(
+            const QString &variable, const QString &baseDirectory, const QStringList &searchDirs,
+            const ProFile *pro) const;
     QString propertyValue(const QString &val) const;
 
     // for our descendents
-- 
GitLab