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 #include "codehighlighting.h"
0010 
0011 #include "../../interfaces/icore.h"
0012 #include "../../interfaces/ilanguagecontroller.h"
0013 #include "../../interfaces/icompletionsettings.h"
0014 #include "../../util/foregroundlock.h"
0015 #include <debug.h>
0016 
0017 #include "../duchain/declaration.h"
0018 #include "../duchain/types/functiontype.h"
0019 #include "../duchain/types/enumeratortype.h"
0020 #include "../duchain/types/typealiastype.h"
0021 #include "../duchain/types/enumerationtype.h"
0022 #include "../duchain/types/structuretype.h"
0023 #include "../duchain/functiondefinition.h"
0024 #include "../duchain/use.h"
0025 
0026 #include "colorcache.h"
0027 #include "configurablecolors.h"
0028 #include <duchain/parsingenvironment.h>
0029 #include <backgroundparser/backgroundparser.h>
0030 #include <backgroundparser/urlparselock.h>
0031 
0032 #include <KTextEditor/Document>
0033 #include <KTextEditor/MovingInterface>
0034 
0035 using namespace KTextEditor;
0036 
0037 static const float highlightingZDepth = -500;
0038 
0039 #define ifDebug(x)
0040 
0041 namespace KDevelop {
0042 ///@todo Don't highlighting everything, only what is visible on-demand
0043 
0044 CodeHighlighting::CodeHighlighting(QObject* parent)
0045     : QObject(parent)
0046     , m_localColorization(true)
0047     , m_globalColorization(true)
0048 {
0049     qRegisterMetaType<KDevelop::IndexedString>("KDevelop::IndexedString");
0050 
0051     adaptToColorChanges();
0052 
0053     connect(ColorCache::self(), &ColorCache::colorsGotChanged,
0054             this, &CodeHighlighting::adaptToColorChanges);
0055 }
0056 
0057 CodeHighlighting::~CodeHighlighting()
0058 {
0059     qDeleteAll(m_highlights);
0060 }
0061 
0062 void CodeHighlighting::adaptToColorChanges()
0063 {
0064     QMutexLocker lock(&m_dataMutex);
0065     // disable local highlighting if the ratio is set to 0
0066     m_localColorization = ICore::self()->languageController()->completionSettings()->localColorizationLevel() > 0;
0067     // disable global highlighting if the ratio is set to 0
0068     m_globalColorization = ICore::self()->languageController()->completionSettings()->globalColorizationLevel() > 0;
0069 
0070     m_declarationAttributes.clear();
0071     m_definitionAttributes.clear();
0072     m_depthAttributes.clear();
0073     m_referenceAttributes.clear();
0074 }
0075 
0076 KTextEditor::Attribute::Ptr CodeHighlighting::attributeForType(CodeHighlightingType type,
0077                                                                CodeHighlightingContext context,
0078                                                                const QColor& color) const
0079 {
0080     QMutexLocker lock(&m_dataMutex);
0081     KTextEditor::Attribute::Ptr a;
0082     switch (context) {
0083     case CodeHighlightingContext::Definition:
0084         a = m_definitionAttributes[type];
0085         break;
0086 
0087     case CodeHighlightingContext::Declaration:
0088         a = m_declarationAttributes[type];
0089         break;
0090 
0091     case CodeHighlightingContext::Reference:
0092         a = m_referenceAttributes[type];
0093         break;
0094     }
0095 
0096     if (!a || color.isValid()) {
0097         a = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute(*ColorCache::self()->defaultColors()->attribute(
0098                                                                        type)));
0099 
0100         if (context == CodeHighlightingContext::Definition || context == CodeHighlightingContext::Declaration) {
0101             if (ICore::self()->languageController()->completionSettings()->boldDeclarations()) {
0102                 a->setFontBold();
0103             }
0104         }
0105 
0106         if (color.isValid()) {
0107             a->setForeground(color);
0108 //       a->setBackground(QColor(mix(0xffffff-color, backgroundColor(), 255-backgroundTinting)));
0109         } else {
0110             switch (context) {
0111             case CodeHighlightingContext::Definition:
0112                 m_definitionAttributes.insert(type, a);
0113                 break;
0114             case CodeHighlightingContext::Declaration:
0115                 m_declarationAttributes.insert(type, a);
0116                 break;
0117             case CodeHighlightingContext::Reference:
0118                 m_referenceAttributes.insert(type, a);
0119                 break;
0120             }
0121         }
0122     }
0123 
0124     return a;
0125 }
0126 
0127 ColorMap emptyColorMap()
0128 {
0129     ColorMap ret(ColorCache::self()->validColorCount() + 1, nullptr);
0130     return ret;
0131 }
0132 
0133 CodeHighlightingInstance* CodeHighlighting::createInstance() const
0134 {
0135     return new CodeHighlightingInstance(this);
0136 }
0137 
0138 bool CodeHighlighting::hasHighlighting(IndexedString url) const
0139 {
0140     DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(url);
0141     if (tracker) {
0142         QMutexLocker lock(&m_dataMutex);
0143         const auto highlightingIt = m_highlights.constFind(tracker);
0144         return highlightingIt != m_highlights.constEnd() && !(*highlightingIt)->m_highlightedRanges.isEmpty();
0145     }
0146     return false;
0147 }
0148 
0149 void CodeHighlighting::highlightDUChain(ReferencedTopDUContext context)
0150 {
0151     ENSURE_CHAIN_NOT_LOCKED
0152 
0153     IndexedString url;
0154 
0155     {
0156         DUChainReadLocker lock;
0157         if (!context)
0158             return;
0159 
0160         url = context->url();
0161     }
0162 
0163     // This prevents the background-parser from updating the top-context while we're working with it
0164     UrlParseLock urlLock(context->url());
0165 
0166     DUChainReadLocker lock;
0167 
0168     qint64 revision = context->parsingEnvironmentFile()->modificationRevision().revision;
0169 
0170     qCDebug(LANGUAGE) << "highlighting du chain" << url.toUrl();
0171 
0172     if (!m_localColorization && !m_globalColorization) {
0173         qCDebug(LANGUAGE) << "highlighting disabled";
0174         QMetaObject::invokeMethod(this, "clearHighlightingForDocument", Qt::QueuedConnection,
0175                                   Q_ARG(KDevelop::IndexedString, url));
0176         return;
0177     }
0178 
0179     CodeHighlightingInstance* instance = createInstance();
0180 
0181     lock.unlock();
0182 
0183     instance->highlightDUChain(context.data());
0184 
0185     auto* highlighting = new DocumentHighlighting;
0186     highlighting->m_document = url;
0187     highlighting->m_waitingRevision = revision;
0188     highlighting->m_waiting = instance->m_highlight;
0189     std::sort(highlighting->m_waiting.begin(), highlighting->m_waiting.end());
0190 
0191     QMetaObject::invokeMethod(this, "applyHighlighting", Qt::QueuedConnection, Q_ARG(void*, highlighting));
0192 
0193     delete instance;
0194 }
0195 
0196 void CodeHighlightingInstance::highlightDUChain(TopDUContext* context)
0197 {
0198     m_contextClasses.clear();
0199     m_useClassCache = true;
0200 
0201     //Highlight
0202     highlightDUChain(context, QHash<Declaration*, uint>(), emptyColorMap());
0203 
0204     m_functionColorsForDeclarations.clear();
0205     m_functionDeclarationsForColors.clear();
0206 
0207     m_useClassCache = false;
0208     m_contextClasses.clear();
0209 }
0210 
0211 void CodeHighlightingInstance::highlightDUChain(DUContext* context, QHash<Declaration*, uint> colorsForDeclarations,
0212                                                 ColorMap declarationsForColors)
0213 {
0214     DUChainReadLocker lock;
0215 
0216     TopDUContext* top = context->topContext();
0217 
0218     //Merge the colors from the function arguments
0219     const auto importedParentContexts = context->importedParentContexts();
0220     for (const DUContext::Import& imported : importedParentContexts) {
0221         if (!imported.context(top) ||
0222             (imported.context(top)->type() != DUContext::Other && imported.context(top)->type() != DUContext::Function))
0223             continue;
0224         //For now it's enough simply copying them, because we only pass on colors within function bodies.
0225         const auto functionColorsIt = m_functionColorsForDeclarations.constFind(imported.context(top));
0226         if (functionColorsIt != m_functionColorsForDeclarations.constEnd())
0227             colorsForDeclarations = *functionColorsIt;
0228         const auto functionDeclarationsIt = m_functionDeclarationsForColors.constFind(imported.context(top));
0229         if (functionDeclarationsIt != m_functionDeclarationsForColors.constEnd())
0230             declarationsForColors = *functionDeclarationsIt;
0231     }
0232 
0233     QList<Declaration*> takeFreeColors;
0234 
0235     bool noRainbow = ICore::self()->languageController()->completionSettings()->localColorizationLevel() == 0;
0236     const auto localDeclarations = context->localDeclarations();
0237     for (Declaration* dec : localDeclarations) {
0238         if (noRainbow || !useRainbowColor(dec)) {
0239             highlightDeclaration(dec, QColor(QColor::Invalid));
0240             continue;
0241         }
0242         //Initially pick a color using the hash, so the chances are good that the same identifier gets the same color always.
0243         uint colorNum = dec->identifier().hash() % ColorCache::self()->primaryColorCount();
0244 
0245         if (declarationsForColors[colorNum]) {
0246             takeFreeColors << dec; //Use one of the colors that stays free
0247             continue;
0248         }
0249 
0250         colorsForDeclarations[dec] = colorNum;
0251         declarationsForColors[colorNum] = dec;
0252 
0253         highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum));
0254     }
0255 
0256     for (Declaration* dec : qAsConst(takeFreeColors)) {
0257         uint colorNum = dec->identifier().hash() % ColorCache::self()->primaryColorCount();
0258         uint oldColorNum = colorNum;
0259         while (declarationsForColors[colorNum]) {
0260             colorNum = (colorNum + 1) % ColorCache::self()->primaryColorCount();
0261             if (colorNum == oldColorNum) {
0262                 colorNum = ColorCache::self()->primaryColorCount();
0263                 break;
0264             }
0265         }
0266 
0267         if (colorNum < ColorCache::self()->primaryColorCount()) {
0268             // Use primary color
0269             colorsForDeclarations[dec] = colorNum;
0270             declarationsForColors[colorNum] = dec;
0271             highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum));
0272         } else {
0273             // Try to use supplementary color
0274             colorNum = ColorCache::self()->primaryColorCount();
0275             while (declarationsForColors[colorNum]) {
0276                 colorNum++;
0277                 if (colorNum == ColorCache::self()->validColorCount()) {
0278                     //If no color could be found, use default color
0279                     highlightDeclaration(dec, QColor(QColor::Invalid));
0280                     break;
0281                 }
0282             }
0283             if (colorNum < ColorCache::self()->validColorCount()) {
0284                 // Use supplementary color
0285                 colorsForDeclarations[dec] = colorNum;
0286                 declarationsForColors[colorNum] = dec;
0287                 highlightDeclaration(dec, ColorCache::self()->generatedColor(colorNum));
0288             }
0289         }
0290     }
0291 
0292     for (int a = 0; a < context->usesCount(); ++a) {
0293         Declaration* decl = context->topContext()->usedDeclarationForIndex(context->uses()[a].m_declarationIndex);
0294         QColor color(QColor::Invalid);
0295         const auto colorsIt = colorsForDeclarations.constFind(decl);
0296         if (colorsIt != colorsForDeclarations.constEnd())
0297             color = ColorCache::self()->generatedColor(*colorsIt);
0298         highlightUse(context, a, color);
0299     }
0300 
0301     if (context->type() == DUContext::Other || context->type() == DUContext::Function) {
0302         const auto indexed = IndexedDUContext(context);
0303         m_functionColorsForDeclarations[indexed] = colorsForDeclarations;
0304         m_functionDeclarationsForColors[indexed] = declarationsForColors;
0305     }
0306 
0307     const QVector<DUContext*> children = context->childContexts();
0308 
0309     lock.unlock(); // Periodically release the lock, so that the UI won't be blocked too much
0310 
0311     for (DUContext* child : children) {
0312         highlightDUChain(child,  colorsForDeclarations, declarationsForColors);
0313     }
0314 }
0315 
0316 KTextEditor::Attribute::Ptr CodeHighlighting::attributeForDepth(int depth) const
0317 {
0318     while (depth >= m_depthAttributes.count()) {
0319         KTextEditor::Attribute::Ptr a(new KTextEditor::Attribute());
0320         a->setBackground(QColor(Qt::white).darker(100 + (m_depthAttributes.count() * 25)));
0321         a->setBackgroundFillWhitespace(true);
0322         if (depth % 2)
0323             a->setOutline(Qt::red);
0324         m_depthAttributes.append(a);
0325     }
0326 
0327     return m_depthAttributes[depth];
0328 }
0329 
0330 KDevelop::Declaration* CodeHighlightingInstance::localClassFromCodeContext(KDevelop::DUContext* context) const
0331 {
0332     if (!context)
0333         return nullptr;
0334 
0335     const auto classIt = m_contextClasses.constFind(context);
0336     if (classIt != m_contextClasses.constEnd())
0337         return *classIt;
0338 
0339     DUContext* startContext = context;
0340 
0341     while (context->type() == DUContext::Other) {
0342         //Move context to the top context of type "Other". This is needed because every compound-statement creates a new sub-context.
0343         auto parent = context->parentContext();
0344         if (!parent || (parent->type() != DUContext::Other && parent->type() != DUContext::Function)) {
0345             break;
0346         }
0347         context = context->parentContext();
0348     }
0349 
0350     ///Step 1: Find the function-declaration for the function we are in
0351     Declaration* functionDeclaration = nullptr;
0352 
0353     if (auto* def = dynamic_cast<FunctionDefinition*>(context->owner())) {
0354         const auto classIt = m_contextClasses.constFind(context);
0355         if (classIt != m_contextClasses.constEnd())
0356             return *classIt;
0357 
0358         functionDeclaration = def->declaration(startContext->topContext());
0359     }
0360 
0361     if (!functionDeclaration && context->owner())
0362         functionDeclaration = context->owner();
0363 
0364     if (!functionDeclaration) {
0365         if (m_useClassCache)
0366             m_contextClasses[context] = nullptr;
0367         return nullptr;
0368     }
0369 
0370     Declaration* decl  = functionDeclaration->context()->owner();
0371 
0372     if (m_useClassCache)
0373         m_contextClasses[context] = decl;
0374 
0375     return decl;
0376 }
0377 
0378 CodeHighlightingType CodeHighlightingInstance::typeForDeclaration(Declaration* dec, DUContext* context) const
0379 {
0380     /**
0381      * We highlight in 3 steps by priority:
0382      * 1. Is the item in the local class or an inherited class? If yes, highlight.
0383      * 2. What kind of item is it? If it's a type/function/enumerator, highlight by type.
0384      * 3. Else, highlight by scope.
0385      *
0386      * */
0387 
0388     if (!dec)
0389         return CodeHighlightingType::Error;
0390 
0391     auto type = CodeHighlightingType::LocalVariable;
0392     if (dec->kind() == Declaration::Namespace)
0393         return CodeHighlightingType::Namespace;
0394 
0395     if (dec->kind() == Declaration::Macro) {
0396         return CodeHighlightingType::Macro;
0397     }
0398 
0399     if (context && dec->context() && dec->context()->type() == DUContext::Class) {
0400         //It is a use.
0401         //Determine the class we're in
0402         Declaration* klass = localClassFromCodeContext(context);
0403         if (klass) {
0404             if (klass->internalContext() == dec->context()) {
0405                 // Using Member of the local class
0406                 if (dec->type<KDevelop::FunctionType>())
0407                     type = CodeHighlightingType::LocalMemberFunction;
0408                 else
0409                     type = CodeHighlightingType::LocalClassMember;
0410             } else if (klass->internalContext() && klass->internalContext()->imports(dec->context())) {
0411                 // Using Member of an inherited clas
0412                 if (dec->type<KDevelop::FunctionType>())
0413                     type = CodeHighlightingType::InheritedMemberFunction;
0414                 else
0415                     type = CodeHighlightingType::InheritedClassMember;
0416             }
0417         }
0418     }
0419 
0420     if (type == CodeHighlightingType::LocalVariable) {
0421         if (dec->kind() == Declaration::Type || dec->type<KDevelop::FunctionType>() ||
0422             dec->type<KDevelop::EnumeratorType>()) {
0423             if (dec->isForwardDeclaration())
0424                 type = CodeHighlightingType::ForwardDeclaration;
0425             else if (dec->type<KDevelop::FunctionType>())
0426                 type = CodeHighlightingType::Function;
0427             else if (dec->type<StructureType>())
0428                 type = CodeHighlightingType::Class;
0429             else if (dec->type<KDevelop::TypeAliasType>())
0430                 type = CodeHighlightingType::TypeAlias;
0431             else if (dec->type<EnumerationType>())
0432                 type = CodeHighlightingType::Enum;
0433             else if (dec->type<KDevelop::EnumeratorType>())
0434                 type = CodeHighlightingType::Enumerator;
0435         }
0436     }
0437 
0438     if (type == CodeHighlightingType::LocalVariable) {
0439         switch (dec->context()->type()) {
0440         case DUContext::Namespace:
0441             type = CodeHighlightingType::NamespaceVariable;
0442             break;
0443         case DUContext::Class:
0444             type = CodeHighlightingType::MemberVariable;
0445             break;
0446         case DUContext::Function:
0447             type = CodeHighlightingType::FunctionVariable;
0448             break;
0449         case DUContext::Global:
0450             type = CodeHighlightingType::GlobalVariable;
0451             break;
0452         default:
0453             break;
0454         }
0455     }
0456 
0457     return type;
0458 }
0459 
0460 bool CodeHighlightingInstance::useRainbowColor(Declaration* dec) const
0461 {
0462     return dec->context()->type() == DUContext::Function ||
0463            (dec->context()->type() == DUContext::Other && dec->context()->owner());
0464 }
0465 
0466 void CodeHighlightingInstance::highlightDeclaration(Declaration* declaration, const QColor& color)
0467 {
0468     HighlightedRange h;
0469     h.range = declaration->range();
0470     h.attribute = m_highlighting->attributeForType(typeForDeclaration(declaration, nullptr),
0471                                                    CodeHighlightingContext::Declaration, color);
0472     m_highlight.push_back(h);
0473 }
0474 
0475 void CodeHighlightingInstance::highlightUse(DUContext* context, int index, const QColor& color)
0476 {
0477     Declaration* decl = context->topContext()->usedDeclarationForIndex(context->uses()[index].m_declarationIndex);
0478 
0479     auto type = typeForDeclaration(decl, context);
0480 
0481     if (type != CodeHighlightingType::Error
0482         || ICore::self()->languageController()->completionSettings()->highlightSemanticProblems()) {
0483         HighlightedRange h;
0484         h.range = context->uses()[index].m_range;
0485         h.attribute = m_highlighting->attributeForType(type, CodeHighlightingContext::Reference, color);
0486         m_highlight.push_back(h);
0487     }
0488 }
0489 
0490 void CodeHighlightingInstance::highlightUses(DUContext* context)
0491 {
0492     for (int a = 0; a < context->usesCount(); ++a)
0493         highlightUse(context, a, QColor(QColor::Invalid));
0494 }
0495 
0496 void CodeHighlighting::clearHighlightingForDocument(const IndexedString& document)
0497 {
0498     VERIFY_FOREGROUND_LOCKED
0499     QMutexLocker lock(&m_dataMutex);
0500     DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(document);
0501     auto highlightingIt = m_highlights.find(tracker);
0502     if (highlightingIt != m_highlights.end()) {
0503         disconnect(tracker, &DocumentChangeTracker::destroyed, this, nullptr);
0504         auto& highlighting = *highlightingIt;
0505         qDeleteAll(highlighting->m_highlightedRanges);
0506         delete highlighting;
0507         m_highlights.erase(highlightingIt);
0508     }
0509 }
0510 
0511 void CodeHighlighting::applyHighlighting(void* _highlighting)
0512 {
0513     auto* highlighting =
0514         static_cast<CodeHighlighting::DocumentHighlighting*>(_highlighting);
0515 
0516     VERIFY_FOREGROUND_LOCKED
0517     QMutexLocker lock(&m_dataMutex);
0518     DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()->trackerForUrl(
0519         highlighting->m_document);
0520 
0521     if (!tracker) {
0522         qCDebug(LANGUAGE) << "no document found for the planned highlighting of" << highlighting->m_document.str();
0523         delete highlighting;
0524         return;
0525     }
0526 
0527     if (!tracker->holdingRevision(highlighting->m_waitingRevision)) {
0528         qCDebug(LANGUAGE) << "not holding revision" << highlighting->m_waitingRevision << "not applying highlighting;"
0529                           << "probably a new parse job has already updated the context";
0530         delete highlighting;
0531         return;
0532     }
0533 
0534     QVector<MovingRange*> oldHighlightedRanges;
0535 
0536     const auto highlightingIt = m_highlights.find(tracker);
0537     if (highlightingIt != m_highlights.end()) {
0538         oldHighlightedRanges = (*highlightingIt)->m_highlightedRanges;
0539         delete *highlightingIt;
0540         *highlightingIt = highlighting;
0541     } else {
0542         // we newly add this tracker, so add the connection
0543         // This can't use new style connect syntax since MovingInterface is not a QObject
0544         connect(tracker->document(), SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)),
0545                 this, SLOT(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)));
0546         connect(tracker->document(), SIGNAL(aboutToRemoveText(KTextEditor::Range)),
0547                 this, SLOT(aboutToRemoveText(KTextEditor::Range)));
0548         connect(tracker, &DocumentChangeTracker::destroyed, this, [this, tracker]() {
0549             // Called when a document is destroyed
0550             VERIFY_FOREGROUND_LOCKED
0551             QMutexLocker lock(&m_dataMutex);
0552             Q_ASSERT(m_highlights.contains(tracker));
0553             delete m_highlights[tracker]; // No need to care about the individual ranges, as the document is being
0554                                           // destroyed
0555             m_highlights.remove(tracker);
0556         });
0557         m_highlights.insert(tracker, highlighting);
0558     }
0559 
0560     // Now create MovingRanges (match old ones with the incoming ranges)
0561 
0562     KTextEditor::Range tempRange;
0563 
0564     QVector<MovingRange*>::iterator movingIt = oldHighlightedRanges.begin();
0565     QVector<HighlightedRange>::iterator rangeIt = highlighting->m_waiting.begin();
0566 
0567     while (rangeIt != highlighting->m_waiting.end()) {
0568         // Translate the range into the current revision
0569         KTextEditor::Range transformedRange = tracker->transformToCurrentRevision(rangeIt->range,
0570                                                                                   highlighting->m_waitingRevision);
0571 
0572         while (movingIt != oldHighlightedRanges.end() &&
0573                ((*movingIt)->start().line() < transformedRange.start().line() ||
0574                 ((*movingIt)->start().line() == transformedRange.start().line() &&
0575                  (*movingIt)->start().column() < transformedRange.start().column()))) {
0576             delete *movingIt; // Skip ranges that are in front of the current matched range
0577             ++movingIt;
0578         }
0579 
0580         tempRange = transformedRange;
0581 
0582         if (movingIt == oldHighlightedRanges.end() ||
0583             transformedRange.start().line() != (*movingIt)->start().line() ||
0584             transformedRange.start().column() != (*movingIt)->start().column() ||
0585             transformedRange.end().line() != (*movingIt)->end().line() ||
0586             transformedRange.end().column() != (*movingIt)->end().column()) {
0587             Q_ASSERT(rangeIt->attribute);
0588             // The moving range is behind or unequal, create a new range
0589             highlighting->m_highlightedRanges.push_back(tracker->documentMovingInterface()->newMovingRange(tempRange));
0590             highlighting->m_highlightedRanges.back()->setAttribute(rangeIt->attribute);
0591             highlighting->m_highlightedRanges.back()->setZDepth(highlightingZDepth);
0592         } else
0593         {
0594             // Update the existing moving range
0595             (*movingIt)->setAttribute(rangeIt->attribute);
0596             (*movingIt)->setRange(tempRange);
0597             highlighting->m_highlightedRanges.push_back(*movingIt);
0598             ++movingIt;
0599         }
0600         ++rangeIt;
0601     }
0602 
0603     for (; movingIt != oldHighlightedRanges.end(); ++movingIt)
0604         delete *movingIt; // Delete unmatched moving ranges behind
0605 }
0606 
0607 void CodeHighlighting::aboutToInvalidateMovingInterfaceContent(Document* doc)
0608 {
0609     clearHighlightingForDocument(IndexedString(doc->url()));
0610 }
0611 
0612 void CodeHighlighting::aboutToRemoveText(const KTextEditor::Range& range)
0613 {
0614     if (range.onSingleLine()) // don't try to optimize this
0615         return;
0616 
0617     VERIFY_FOREGROUND_LOCKED
0618     QMutexLocker lock(&m_dataMutex);
0619     Q_ASSERT(qobject_cast<KTextEditor::Document*>(sender()));
0620     auto* doc = static_cast<KTextEditor::Document*>(sender());
0621 
0622     DocumentChangeTracker* tracker = ICore::self()->languageController()->backgroundParser()
0623                                      ->trackerForUrl(IndexedString(doc->url()));
0624     const auto highlightingIt = m_highlights.constFind(tracker);
0625     if (highlightingIt != m_highlights.constEnd()) {
0626         QVector<MovingRange*>& ranges = (*highlightingIt)->m_highlightedRanges;
0627         QVector<MovingRange*>::iterator it = ranges.begin();
0628         while (it != ranges.end()) {
0629             if (range.contains((*it)->toRange())) {
0630                 delete (*it);
0631                 it = ranges.erase(it);
0632             } else {
0633                 ++it;
0634             }
0635         }
0636     }
0637 }
0638 }
0639 
0640 #include "moc_codehighlighting.cpp"