File indexing completed on 2024-05-12 05:52:03

0001 /*
0002     SPDX-FileCopyrightText: 2019 Mark Nauwelaerts <mark.nauwelaerts@gmail.com>
0003     SPDX-FileCopyrightText: 2022 Waqar Ahmed <waqar.17a@gmail.com>
0004     SPDX-License-Identifier: MIT
0005 */
0006 #pragma once
0007 
0008 #include "diagnostic_suppression.h"
0009 #include "diagnostic_types.h"
0010 #include "diagnosticview.h"
0011 
0012 #include <QStandardItem>
0013 
0014 namespace DiagnosticModelRole
0015 {
0016 enum {
0017     // preserve UserRole for generic use where needed
0018     FileUrlRole = Qt::UserRole + 1,
0019     RangeRole,
0020     KindRole,
0021     ProviderRole,
0022 };
0023 }
0024 
0025 enum {
0026     DiagnosticItem_File = QStandardItem::UserType + 1,
0027     DiagnosticItem_Diag,
0028     DiagnosticItem_Fix,
0029 };
0030 
0031 // custom item subclass that captures additional attributes;
0032 // a bit more convenient than the variant/role way
0033 struct DiagnosticItem : public QStandardItem {
0034     Diagnostic m_diagnostic;
0035 
0036     explicit DiagnosticItem(const Diagnostic &d)
0037         : m_diagnostic(d)
0038     {
0039     }
0040 
0041     int type() const override
0042     {
0043         return DiagnosticItem_Diag;
0044     }
0045 
0046     bool hasFixes() const
0047     {
0048         if (!hasChildren()) {
0049             return false;
0050         }
0051         for (int i = 0; i < rowCount(); ++i) {
0052             if (child(i)->type() == DiagnosticItem_Fix) {
0053                 return true;
0054             }
0055         }
0056         return false;
0057     }
0058 };
0059 
0060 // likewise; a custom item for document level model item
0061 struct DocumentDiagnosticItem : public QStandardItem {
0062 private:
0063     QList<DiagnosticsProvider *> m_providers;
0064 
0065 public:
0066     bool enabled = true;
0067     std::unique_ptr<DiagnosticSuppression> diagnosticSuppression;
0068     int type() const override
0069     {
0070         return DiagnosticItem_File;
0071     }
0072 
0073     const QList<DiagnosticsProvider *> &providers() const
0074     {
0075         return m_providers;
0076     }
0077     void addProvider(DiagnosticsProvider *p)
0078     {
0079         if (!m_providers.contains(p)) {
0080             m_providers.push_back(p);
0081         }
0082     }
0083 
0084     /**
0085      * Remove items for given provider. If p == null, remove all items of the file
0086      * except the items whose provider has m_persistentDiagnostics.
0087      */
0088     int removeItemsForProvider(DiagnosticsProvider *p)
0089     {
0090         int removedCount = 0;
0091         if (m_providers.size() == 1) {
0092             if (p == nullptr && m_providers.back()->persistentDiagnostics()) {
0093                 // If there is only 1 provider and it's diagnostics are persistent, we have nothing to do here
0094                 return removedCount;
0095             } else if (m_providers.contains(p)) {
0096                 m_providers.clear();
0097                 removedCount = rowCount();
0098                 setRowCount(0);
0099                 return removedCount;
0100             } else {
0101                 // if we don't have any diagnostics from this provider, we have nothing to do
0102                 return removedCount;
0103             }
0104         }
0105 
0106         QVarLengthArray<DiagnosticsProvider *, 3> removedProviders;
0107         auto removeProvider = [&removedProviders](DiagnosticsProvider *p) {
0108             if (!removedProviders.contains(p)) {
0109                 removedProviders.append(p);
0110             }
0111         };
0112         // We have more than one diagnostic provider for this file
0113         if (p == nullptr) {
0114             // Remove all diagnostics where provider->persistentDiagnostics() == false
0115             int start = -1;
0116             int count = 0;
0117             for (int i = 0; i < rowCount(); ++i) {
0118                 auto item = child(i);
0119                 auto itemProvider = item->data(DiagnosticModelRole::ProviderRole).value<DiagnosticsProvider *>();
0120                 if (!itemProvider->persistentDiagnostics()) {
0121                     if (start == -1) {
0122                         start = i;
0123                     }
0124                     count++;
0125                     removeProvider(itemProvider);
0126                 } else {
0127                     if (start > -1 && count != 0) {
0128                         removedCount += count;
0129                         removeRows(start, count);
0130                         i = start - 1;
0131                         start = -1;
0132                         count = 0;
0133                     }
0134                 }
0135             }
0136             if (start > -1 && count != 0) {
0137                 removedCount += count;
0138                 removeRows(start, count);
0139             }
0140         } else {
0141             // remove all diagnostics from the given provider
0142             int start = -1;
0143             int count = 0;
0144             for (int i = 0; i < rowCount(); ++i) {
0145                 auto item = child(i);
0146                 auto itemProvider = item->data(DiagnosticModelRole::ProviderRole).value<DiagnosticsProvider *>();
0147                 if (itemProvider == p) {
0148                     if (start == -1) {
0149                         start = i;
0150                     }
0151                     removeProvider(itemProvider);
0152                     count++;
0153                 } else {
0154                     if (start > -1 && count != 0) {
0155                         removedCount += count;
0156                         removeRows(start, count);
0157                         i = start - 1;
0158                         start = -1;
0159                         count = 0;
0160                     }
0161                 }
0162             }
0163             if (start > -1 && count != 0) {
0164                 removedCount += count;
0165                 removeRows(start, count);
0166             }
0167         }
0168 
0169         // remove the providers for which we don't have diagnostics
0170         for (auto p : removedProviders) {
0171             m_providers.removeOne(p);
0172         }
0173         return removedCount;
0174     }
0175 };
0176 
0177 struct DiagnosticFixItem : public QStandardItem {
0178     DiagnosticFix fix;
0179     int type() const override
0180     {
0181         return DiagnosticItem_Fix;
0182     }
0183 };