From 21b0e7c37e8f04dfc763852089174b51d5675a1c Mon Sep 17 00:00:00 2001
From: Tobias Hunger <tobias.hunger@qt.io>
Date: Mon, 30 Oct 2017 16:59:46 +0100
Subject: [PATCH] Qmake: Make finding pro-files fast

Finding the right pro-file was surprisingly slow. Make that fast again.

Task-number: QTCREATORBUG-19131
Change-Id: I4b5a8887cb13c36273a553f935a00d87cee4a7b5
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
---
 src/plugins/qmakeprojectmanager/qmakenodes.cpp  | 17 +++++++++--------
 src/plugins/qmakeprojectmanager/qmakenodes.h    |  5 +++--
 .../qmakenodetreebuilder.cpp                    | 10 +++++-----
 .../qmakeprojectmanager/qmakeparsernodes.cpp    | 17 ++++++++++++-----
 .../qmakeprojectmanager/qmakeparsernodes.h      |  2 ++
 5 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp
index f19723df95..2d0ff67465 100644
--- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp
@@ -44,20 +44,21 @@ namespace QmakeProjectManager {
   */
 
 QmakePriFileNode::QmakePriFileNode(QmakeProject *project, QmakeProFileNode *qmakeProFileNode,
-                                   const FileName &filePath) :
+                                   const FileName &filePath, QmakePriFile *pf) :
     ProjectNode(filePath),
     m_project(project),
-    m_qmakeProFileNode(qmakeProFileNode)
+    m_qmakeProFileNode(qmakeProFileNode),
+    m_qmakePriFile(pf)
 { }
 
 QmakePriFile *QmakePriFileNode::priFile() const
 {
-    return m_project->rootProFile()->findPriFile(filePath());
+    return m_qmakePriFile;
 }
 
 bool QmakePriFileNode::deploysFolder(const QString &folder) const
 {
-    QmakePriFile *pri = priFile();
+    const QmakePriFile *pri = priFile();
     return pri ? pri->deploysFolder(folder) : false;
 }
 
@@ -145,7 +146,7 @@ bool QmakePriFileNode::supportsAction(ProjectAction action, const Node *node) co
 
 bool QmakePriFileNode::canAddSubProject(const QString &proFilePath) const
 {
-    QmakePriFile *pri = priFile();
+    const QmakePriFile *pri = priFile();
     return pri ? pri->canAddSubProject(proFilePath) : false;
 }
 
@@ -213,8 +214,8 @@ QmakeProFileNode *QmakeProFileNode::findProFileFor(const FileName &fileName) con
   \class QmakeProFileNode
   Implements abstract ProjectNode class
   */
-QmakeProFileNode::QmakeProFileNode(QmakeProject *project, const FileName &filePath) :
-    QmakePriFileNode(project, this, filePath)
+QmakeProFileNode::QmakeProFileNode(QmakeProject *project, const FileName &filePath, QmakeProFile *pf) :
+    QmakePriFileNode(project, this, filePath, pf)
 { }
 
 bool QmakeProFileNode::showInSimpleTree() const
@@ -224,7 +225,7 @@ bool QmakeProFileNode::showInSimpleTree() const
 
 QmakeProFile *QmakeProFileNode::proFile() const
 {
-    return m_project->rootProFile()->findProFile(filePath());
+    return static_cast<QmakeProFile*>(QmakePriFileNode::priFile());
 }
 
 FolderNode::AddNewInformation QmakeProFileNode::addNewInformation(const QStringList &files, Node *context) const
diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h
index aca17e18a2..56a2b6be62 100644
--- a/src/plugins/qmakeprojectmanager/qmakenodes.h
+++ b/src/plugins/qmakeprojectmanager/qmakenodes.h
@@ -42,7 +42,7 @@ class QMAKEPROJECTMANAGER_EXPORT QmakePriFileNode : public ProjectExplorer::Proj
 {
 public:
     QmakePriFileNode(QmakeProject *project, QmakeProFileNode *qmakeProFileNode,
-                     const Utils::FileName &filePath);
+                     const Utils::FileName &filePath, QmakePriFile *pf);
 
     QmakePriFile *priFile() const;
 
@@ -73,13 +73,14 @@ protected:
 
 private:
     QmakeProFileNode *m_qmakeProFileNode = nullptr;
+    QmakePriFile *m_qmakePriFile = nullptr;
 };
 
 // Implements ProjectNode for qmake .pro files
 class QMAKEPROJECTMANAGER_EXPORT QmakeProFileNode : public QmakePriFileNode
 {
 public:
-    QmakeProFileNode(QmakeProject *project, const Utils::FileName &filePath);
+    QmakeProFileNode(QmakeProject *project, const Utils::FileName &filePath, QmakeProFile *pf);
 
     QmakeProFile *proFile() const;
 
diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp
index a65b9cd44b..6e071c90e0 100644
--- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp
@@ -183,12 +183,12 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node, const Fi
     }
 
     // Virtual folders:
-    for (const QmakePriFile *c : pri->children()) {
+    for (QmakePriFile *c : pri->children()) {
         QmakePriFileNode *newNode = nullptr;
-        if (dynamic_cast<const QmakeProFile *>(c))
-            newNode = new QmakeProFileNode(c->project(), c->filePath());
+        if (auto pf = dynamic_cast<QmakeProFile *>(c))
+            newNode = new QmakeProFileNode(c->project(), c->filePath(), pf);
         else
-            newNode = new QmakePriFileNode(c->project(), node->proFileNode(), c->filePath());
+            newNode = new QmakePriFileNode(c->project(), node->proFileNode(), c->filePath(), c);
         createTree(c, newNode, toExclude);
         node->addNode(newNode);
     }
@@ -203,7 +203,7 @@ QmakeProFileNode *QmakeNodeTreeBuilder::buildTree(QmakeProject *project)
 
     const FileNameList toExclude = qt ? qt->directoriesToIgnoreInProjectTree() : FileNameList();
 
-    auto root = new QmakeProFileNode(project, project->projectFilePath());
+    auto root = new QmakeProFileNode(project, project->projectFilePath(), project->rootProFile());
     createTree(project->rootProFile(), root, toExclude);
 
     return root;
diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
index 1c3f4962aa..d37a61626c 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
+++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp
@@ -199,12 +199,14 @@ QmakePriFile *QmakePriFile::findPriFile(const FileName &fileName)
 {
     if (fileName == filePath())
         return this;
-    for (QmakePriFile *n : children()) {
-        if (QmakePriFile *result = n->findPriFile(fileName))
-            return result;
-    }
-    return nullptr;
+    return findOrDefault(m_children, [&fileName](QmakePriFile *pf) { return pf->findPriFile(fileName); });
+}
 
+const QmakePriFile *QmakePriFile::findPriFile(const FileName &fileName) const
+{
+    if (fileName == filePath())
+        return this;
+    return findOrDefault(m_children, [&fileName](const QmakePriFile *pf) { return pf->findPriFile(fileName); });
 }
 
 void QmakePriFile::makeEmpty()
@@ -1010,6 +1012,11 @@ QmakeProFile *QmakeProFile::findProFile(const FileName &fileName)
     return dynamic_cast<QmakeProFile *>(findPriFile(fileName));
 }
 
+const QmakeProFile *QmakeProFile::findProFile(const FileName &fileName) const
+{
+    return dynamic_cast<const QmakeProFile *>(findPriFile(fileName));
+}
+
 QString QmakeProFile::makefile() const
 {
     return singleVariableValue(Variable::Makefile);
diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h
index 2cad1340cc..41138f4563 100644
--- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h
+++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h
@@ -121,6 +121,7 @@ public:
     QVector<QmakePriFile *> children() const;
 
     QmakePriFile *findPriFile(const Utils::FileName &fileName);
+    const QmakePriFile *findPriFile(const Utils::FileName &fileName) const;
 
     bool knowsFile(const Utils::FileName &filePath) const;
 
@@ -280,6 +281,7 @@ public:
 
     QList<QmakeProFile *> allProFiles();
     QmakeProFile *findProFile(const Utils::FileName &fileName);
+    const QmakeProFile *findProFile(const Utils::FileName &fileName) const;
 
     ProjectType projectType() const;
 
-- 
GitLab