From 07e809fb6b925cc0a6c2d6e25b02fcedf3dfb987 Mon Sep 17 00:00:00 2001
From: Philip Van Hoof <philip@codeminded.be>
Date: Fri, 14 Oct 2022 17:27:14 +0200
Subject: [PATCH] cppeditor: make it possible to ignore patterns

Allows the user to ignore certain patterns so that these files wont
be indexed
---
 .../cppeditor/cppcodemodelsettings.cpp        | 35 +++++++++++++++++++
 src/plugins/cppeditor/cppcodemodelsettings.h  |  7 ++++
 .../cppeditor/cppcodemodelsettingspage.cpp    | 21 +++++++++++
 src/plugins/cppeditor/cppeditorconstants.h    |  2 ++
 src/plugins/cppeditor/cppmodelmanager.cpp     | 33 ++++++++++++++++-
 5 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp
index 18512cf10c..4bb98af0c3 100644
--- a/src/plugins/cppeditor/cppcodemodelsettings.cpp
+++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp
@@ -45,6 +45,12 @@ static QString interpretAmbiguousHeadersAsCHeadersKey()
 static QString skipIndexingBigFilesKey()
 { return QLatin1String(Constants::CPPEDITOR_SKIP_INDEXING_BIG_FILES); }
 
+static QString ignoreFilesKey()
+{ return QLatin1String(Constants::CPPEDITOR_IGNORE_FILES); }
+
+static QString ignorePatternKey()
+{ return QLatin1String(Constants::CPPEDITOR_IGNORE_PATTERN); }
+
 static QString useBuiltinPreprocessorKey()
 { return QLatin1String(Constants::CPPEDITOR_USE_BUILTIN_PREPROCESSOR); }
 
@@ -91,6 +97,12 @@ void CppCodeModelSettings::fromSettings(QSettings *s)
     const QVariant skipIndexingBigFiles = s->value(skipIndexingBigFilesKey(), true);
     setSkipIndexingBigFiles(skipIndexingBigFiles.toBool());
 
+    const QVariant ignoreFiles = s->value(ignoreFilesKey(), false);
+    setIgnoreFiles(ignoreFiles.toBool());
+
+    const QVariant ignorePattern = s->value(ignorePatternKey(), "");
+    setIgnorePattern(ignorePattern.toString());
+
     setUseBuiltinPreprocessor(s->value(useBuiltinPreprocessorKey(), true).toBool());
 
     const QVariant indexerFileSizeLimit = s->value(indexerFileSizeLimitKey(), 5);
@@ -110,6 +122,8 @@ void CppCodeModelSettings::toSettings(QSettings *s)
 
     s->setValue(interpretAmbiguousHeadersAsCHeadersKey(), interpretAmbigiousHeadersAsCHeaders());
     s->setValue(skipIndexingBigFilesKey(), skipIndexingBigFiles());
+    s->setValue(ignoreFilesKey(), ignoreFiles());
+    s->setValue(ignorePatternKey(), QVariant(ignorePattern()));
     s->setValue(useBuiltinPreprocessorKey(), useBuiltinPreprocessor());
     s->setValue(indexerFileSizeLimitKey(), indexerFileSizeLimitInMb());
 
@@ -158,6 +172,27 @@ void CppCodeModelSettings::setIndexerFileSizeLimitInMb(int sizeInMB)
     m_indexerFileSizeLimitInMB = sizeInMB;
 }
 
+bool CppCodeModelSettings::ignoreFiles() const
+{
+   return m_ignoreFiles;
+}
+
+void CppCodeModelSettings::setIgnoreFiles(bool ignoreFiles)
+{
+    m_ignoreFiles = ignoreFiles;
+}
+
+QString CppCodeModelSettings::ignorePattern() const
+{
+   return m_ignorePattern;
+}
+
+void CppCodeModelSettings::setIgnorePattern(const QString& ignorePattern)
+{
+    m_ignorePattern = ignorePattern;
+}
+
+
 bool CppCodeModelSettings::enableLowerClazyLevels() const
 {
     return m_enableLowerClazyLevels;
diff --git a/src/plugins/cppeditor/cppcodemodelsettings.h b/src/plugins/cppeditor/cppcodemodelsettings.h
index cd010eec99..02d480d68e 100644
--- a/src/plugins/cppeditor/cppcodemodelsettings.h
+++ b/src/plugins/cppeditor/cppcodemodelsettings.h
@@ -57,6 +57,11 @@ public:
     void setCategorizeFindReferences(bool categorize) { m_categorizeFindReferences = categorize; }
     bool categorizeFindReferences() const { return m_categorizeFindReferences; }
 
+    bool ignoreFiles() const;
+    void setIgnoreFiles(bool ignoreFiles);
+    QString ignorePattern() const;
+    void setIgnorePattern(const QString& ignorePattern);
+
 signals:
     void clangDiagnosticConfigsInvalidated(const QVector<Utils::Id> &configId);
     void changed();
@@ -69,6 +74,8 @@ private:
     int m_indexerFileSizeLimitInMB = 5;
     bool m_enableLowerClazyLevels = true; // For UI behavior only
     bool m_categorizeFindReferences = false; // Ephemeral!
+    bool m_ignoreFiles = false;
+    QString m_ignorePattern;
 };
 
 class CPPEDITOR_EXPORT ClangdSettings : public QObject
diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
index 476a3dae5c..ec24cb1fa3 100644
--- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
+++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
@@ -31,6 +31,7 @@
 #include <QTextStream>
 #include <QVBoxLayout>
 #include <QVersionNumber>
+#include <QTextBlock>
 
 #include <limits>
 
@@ -54,6 +55,8 @@ private:
     QCheckBox *m_useBuiltinPreprocessorCheckBox;
     QCheckBox *m_skipIndexingBigFilesCheckBox;
     QSpinBox *m_bigFilesLimitSpinBox;
+    QCheckBox *m_ignoreFilesCheckBox;
+    QPlainTextEdit *m_ignorePatternTextEdit;
 };
 
 CppCodeModelSettingsWidget::CppCodeModelSettingsWidget(CppCodeModelSettings *s)
@@ -70,6 +73,13 @@ CppCodeModelSettingsWidget::CppCodeModelSettingsWidget(CppCodeModelSettings *s)
     m_bigFilesLimitSpinBox->setRange(1, 500);
     m_bigFilesLimitSpinBox->setValue(m_settings->indexerFileSizeLimitInMb());
 
+    m_ignoreFilesCheckBox = new QCheckBox(tr("Ignore files"));
+    m_ignoreFilesCheckBox->setToolTip(tr(
+        "<html><head/><body><p>Ignore files that match these wildcard patterns, one wildcard per line.</p></body></html>"));
+
+    m_ignoreFilesCheckBox->setChecked(m_settings->ignoreFiles());
+    m_ignorePatternTextEdit = new QPlainTextEdit(m_settings->ignorePattern());
+
     m_ignorePchCheckBox = new QCheckBox(tr("Ignore precompiled headers"));
     m_ignorePchCheckBox->setToolTip(tr(
         "<html><head/><body><p>When precompiled headers are not ignored, the parsing for code "
@@ -98,6 +108,7 @@ CppCodeModelSettingsWidget::CppCodeModelSettingsWidget(CppCodeModelSettings *s)
                 m_ignorePchCheckBox,
                 m_useBuiltinPreprocessorCheckBox,
                 Row { m_skipIndexingBigFilesCheckBox, m_bigFilesLimitSpinBox, st },
+                Row { m_ignoreFilesCheckBox, m_ignorePatternTextEdit, st },
             }
         },
         st
@@ -132,6 +143,16 @@ bool CppCodeModelSettingsWidget::applyGeneralWidgetsToSettings() const
         m_settings->setUseBuiltinPreprocessor(newUseBuiltinPreprocessor);
         settingsChanged = true;
     }
+    const bool ignoreFiles = m_ignoreFilesCheckBox->isChecked();
+    if (m_settings->ignoreFiles() != ignoreFiles) {
+        m_settings->setIgnoreFiles(ignoreFiles);
+        settingsChanged = true;
+    }
+    const QString ignorePattern = m_ignorePatternTextEdit->toPlainText();
+    if (m_settings->ignorePattern() != ignorePattern) {
+        m_settings->setIgnorePattern(ignorePattern);
+        settingsChanged = true;
+    }
     const int newFileSizeLimit = m_bigFilesLimitSpinBox->value();
     if (m_settings->indexerFileSizeLimitInMb() != newFileSizeLimit) {
         m_settings->setIndexerFileSizeLimitInMb(newFileSizeLimit);
diff --git a/src/plugins/cppeditor/cppeditorconstants.h b/src/plugins/cppeditor/cppeditorconstants.h
index 0c226f6682..1bb6a2eafe 100644
--- a/src/plugins/cppeditor/cppeditorconstants.h
+++ b/src/plugins/cppeditor/cppeditorconstants.h
@@ -89,6 +89,8 @@ const char CPPEDITOR_INTERPRET_AMBIGIUOUS_HEADERS_AS_C_HEADERS[]
 const char CPPEDITOR_USE_BUILTIN_PREPROCESSOR[] = "UseBuiltinPreprocessor";
 const char CPPEDITOR_SKIP_INDEXING_BIG_FILES[] = "SkipIndexingBigFiles";
 const char CPPEDITOR_INDEXER_FILE_SIZE_LIMIT[] = "IndexerFileSizeLimit";
+const char CPPEDITOR_IGNORE_FILES[] = "IgnoreFiles";
+const char CPPEDITOR_IGNORE_PATTERN[] = "IgnorePattern";
 
 const char CPP_CLANG_DIAG_CONFIG_QUESTIONABLE[] = "Builtin.Questionable";
 const char CPP_CLANG_DIAG_CONFIG_BUILDSYSTEM[] = "Builtin.BuildSystem";
diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp
index da8fdb53f6..816afda578 100644
--- a/src/plugins/cppeditor/cppmodelmanager.cpp
+++ b/src/plugins/cppeditor/cppmodelmanager.cpp
@@ -72,6 +72,7 @@
 #include <QThreadPool>
 #include <QTimer>
 #include <QWriteLocker>
+#include <QRegExp>
 
 #if defined(QTCREATOR_WITH_DUMP_AST) && defined(Q_CC_GNU)
 #define WITH_AST_DUMP
@@ -1068,13 +1069,43 @@ static QSet<QString> tooBigFilesRemoved(const QSet<QString> &files, int fileSize
     return result;
 }
 
+static QSet<QString> ignoredFilesRemoved(const QSet<QString> &files, const QString& ignorePattern)
+{
+    QSet<QString> newFiles = files;
+    QStringList wildcards = ignorePattern.split('\n');
+    for (const QString& wildcard : wildcards) {
+        QRegExp rx(wildcard);
+        rx.setPatternSyntax(QRegExp::Wildcard);
+        for (const QString& filePath : files) {
+            if (rx.exactMatch(filePath)) {
+                const QString msg = QCoreApplication::translate(
+                            "CppIndexer",
+                            "C++ Indexer: Skipping file \"%1\" because its path matches the ignore pattern.")
+                                .arg(filePath);
+
+                QMetaObject::invokeMethod(Core::MessageManager::instance(),
+                                          [msg]() { Core::MessageManager::writeSilently(msg); });
+                newFiles.remove(filePath);
+            }
+        }
+    }
+
+    return newFiles;
+}
+
 QFuture<void> CppModelManager::updateSourceFiles(const QSet<QString> &sourceFiles,
                                                  ProgressNotificationMode mode)
 {
     if (sourceFiles.isEmpty() || !d->m_indexerEnabled)
         return QFuture<void>();
 
-    const QSet<QString> filteredFiles = tooBigFilesRemoved(sourceFiles, indexerFileSizeLimitInMb());
+    const QSet<QString> notTooBigFiles = tooBigFilesRemoved(sourceFiles, indexerFileSizeLimitInMb());
+    QSet<QString> filteredFiles;
+
+    if (codeModelSettings()->ignoreFiles())
+        filteredFiles = ignoredFilesRemoved(notTooBigFiles, codeModelSettings()->ignorePattern());
+    else
+        filteredFiles = notTooBigFiles;
 
     return d->m_internalIndexingSupport->refreshSourceFiles(filteredFiles, mode);
 }
-- 
2.34.1

