File indexing completed on 2024-05-12 04:38:06

0001 /*
0002     SPDX-FileCopyrightText: 2007-2010 David Nolden <david.nolden.kdevelop@art-master.de>
0003     SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
0004     SPDX-FileCopyrightText: 2009 Milian Wolff <mail@milianw.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #ifndef KDEVPLATFORM_CODEHIGHLIGHTING_H
0010 #define KDEVPLATFORM_CODEHIGHLIGHTING_H
0011 
0012 #include <QObject>
0013 #include <QHash>
0014 #include <QRecursiveMutex>
0015 
0016 #include <serialization/indexedstring.h>
0017 #include <language/duchain/ducontext.h>
0018 #include <language/interfaces/icodehighlighting.h>
0019 #include <language/backgroundparser/documentchangetracker.h>
0020 
0021 #include <KTextEditor/Attribute>
0022 #include <KTextEditor/MovingRange>
0023 
0024 namespace KDevelop {
0025 class DUContext;
0026 class Declaration;
0027 
0028 using ColorMap = QVector<KDevelop::Declaration*>;
0029 
0030 class CodeHighlighting;
0031 
0032 enum class CodeHighlightingType {
0033     Error,
0034 
0035     LocalClassMember,
0036     LocalMemberFunction,
0037     InheritedClassMember,
0038     InheritedMemberFunction,
0039     LocalVariable,
0040     MemberVariable,
0041     NamespaceVariable,
0042     GlobalVariable,
0043     FunctionVariable,
0044 
0045     Class,
0046     Namespace,
0047     Function,
0048     ForwardDeclaration,
0049     Enum,
0050     Enumerator,
0051     TypeAlias,
0052     Macro, ///< Declaration of a macro such as "#define FOO"
0053     MacroFunctionLike, ///< Declaration of a function like macro such as "#define FOO()"
0054     HighlightUses,
0055 };
0056 
0057 inline uint qHash(CodeHighlightingType type, uint seed = 0) noexcept
0058 {
0059     return ::qHash(static_cast<int>(type), seed);
0060 }
0061 
0062 enum class CodeHighlightingContext {
0063     Definition,
0064     Declaration,
0065     Reference,
0066 };
0067 
0068 struct HighlightedRange
0069 {
0070     RangeInRevision range;
0071     KTextEditor::Attribute::Ptr attribute;
0072     bool operator<(const HighlightedRange& rhs) const
0073     {
0074         return range.start < rhs.range.start;
0075     }
0076 };
0077 
0078 /**
0079  * Code highlighting instance that is used to apply code highlighting to one specific top context
0080  * */
0081 
0082 class KDEVPLATFORMLANGUAGE_EXPORT CodeHighlightingInstance
0083 {
0084 public:
0085     explicit CodeHighlightingInstance(const CodeHighlighting* highlighting) : m_useClassCache(false)
0086         , m_highlighting(highlighting)
0087     {
0088     }
0089     virtual ~CodeHighlightingInstance()
0090     {
0091     }
0092 
0093     virtual void highlightDeclaration(KDevelop::Declaration* declaration, const QColor& color);
0094     virtual void highlightUse(KDevelop::DUContext* context, int index, const QColor& color);
0095     virtual void highlightUses(KDevelop::DUContext* context);
0096 
0097     void highlightDUChain(KDevelop::TopDUContext* context);
0098     void highlightDUChain(KDevelop::DUContext* context, QHash<KDevelop::Declaration*, uint> colorsForDeclarations,
0099         ColorMap);
0100 
0101     KDevelop::Declaration* localClassFromCodeContext(KDevelop::DUContext* context) const;
0102     /**
0103      * @param context Should be the context from where the declaration is used, if a use is highlighted.
0104      * */
0105     virtual CodeHighlightingType typeForDeclaration(KDevelop::Declaration* dec, KDevelop::DUContext* context) const;
0106     /**
0107      * Decides whether to apply auto-generated rainbow colors to @p dec.
0108      * Default implementation only applies that to local variables in functions.
0109      */
0110     virtual bool useRainbowColor(KDevelop::Declaration* dec) const;
0111 
0112     //A temporary hash for speedup
0113     mutable QHash<KDevelop::DUContext*, KDevelop::Declaration*> m_contextClasses;
0114 
0115     //Here the colors of function context are stored until they are merged into the function body
0116     mutable QHash<KDevelop::IndexedDUContext, QHash<KDevelop::Declaration*, uint>> m_functionColorsForDeclarations;
0117     mutable QHash<KDevelop::IndexedDUContext, ColorMap> m_functionDeclarationsForColors;
0118 
0119     mutable bool m_useClassCache;
0120     const CodeHighlighting* m_highlighting;
0121 
0122     QVector<HighlightedRange> m_highlight;
0123 };
0124 
0125 /**
0126  * General class representing the code highlighting for one language
0127  * */
0128 class KDEVPLATFORMLANGUAGE_EXPORT CodeHighlighting : public QObject, public KDevelop::ICodeHighlighting
0129 {
0130     Q_OBJECT
0131     Q_INTERFACES(KDevelop::ICodeHighlighting)
0132 
0133 public:
0134 
0135     explicit CodeHighlighting(QObject* parent);
0136     ~CodeHighlighting() override;
0137 
0138     /// This function is thread-safe
0139     /// @warning The duchain must not be locked when this is called (->possible deadlock)
0140     void highlightDUChain(ReferencedTopDUContext context) override;
0141 
0142     //color should be zero when undecided
0143     KTextEditor::Attribute::Ptr attributeForType(CodeHighlightingType type, CodeHighlightingContext context,
0144                                                  const QColor& color) const;
0145     KTextEditor::Attribute::Ptr attributeForDepth(int depth) const;
0146 
0147     /// This function is thread-safe
0148     /// Returns whether a highlighting is already given for the given url
0149     bool hasHighlighting(IndexedString url) const override;
0150 
0151 private:
0152     //Returns whether the given attribute was set by the code highlighting, and not by something else
0153     //Always returns true when the attribute is zero
0154     bool isCodeHighlight(KTextEditor::Attribute::Ptr attr) const;
0155 
0156 protected:
0157     //Can be overridden to create an own instance type
0158     virtual CodeHighlightingInstance* createInstance() const;
0159 
0160 private:
0161 
0162     /// Highlighting of one specific document
0163     struct DocumentHighlighting
0164     {
0165         IndexedString m_document;
0166         qint64 m_waitingRevision;
0167         // The ranges are sorted by range start, so they can easily be matched
0168         QVector<HighlightedRange> m_waiting;
0169         QVector<KTextEditor::MovingRange*> m_highlightedRanges;
0170     };
0171 
0172     QHash<DocumentChangeTracker*, DocumentHighlighting*> m_highlights;
0173 
0174     friend class CodeHighlightingInstance;
0175 
0176     mutable QHash<CodeHighlightingType, KTextEditor::Attribute::Ptr> m_definitionAttributes;
0177     mutable QHash<CodeHighlightingType, KTextEditor::Attribute::Ptr> m_declarationAttributes;
0178     mutable QHash<CodeHighlightingType, KTextEditor::Attribute::Ptr> m_referenceAttributes;
0179     mutable QList<KTextEditor::Attribute::Ptr> m_depthAttributes;
0180     // Should be used to enable/disable the colorization of local variables and their uses
0181     bool m_localColorization;
0182     // Should be used to enable/disable the colorization of global types and their uses
0183     bool m_globalColorization;
0184 
0185     mutable QRecursiveMutex m_dataMutex;
0186 
0187 private Q_SLOTS:
0188     void clearHighlightingForDocument(const KDevelop::IndexedString& document);
0189     void applyHighlighting(void* highlighting);
0190 
0191     /// when the colors change we must invalidate our local caches
0192     void adaptToColorChanges();
0193 
0194     void aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*);
0195     void aboutToRemoveText(const KTextEditor::Range&);
0196 };
0197 }
0198 
0199 Q_DECLARE_TYPEINFO(KDevelop::HighlightedRange, Q_MOVABLE_TYPE);
0200 
0201 #endif