Home | History | Annotate | Line # | Download | only in Format
      1  1.1  joerg //===--- AffectedRangeManager.cpp - Format C++ code -----------------------===//
      2  1.1  joerg //
      3  1.1  joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4  1.1  joerg // See https://llvm.org/LICENSE.txt for license information.
      5  1.1  joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6  1.1  joerg //
      7  1.1  joerg //===----------------------------------------------------------------------===//
      8  1.1  joerg ///
      9  1.1  joerg /// \file
     10  1.1  joerg /// This file implements AffectRangeManager class.
     11  1.1  joerg ///
     12  1.1  joerg //===----------------------------------------------------------------------===//
     13  1.1  joerg 
     14  1.1  joerg #include "AffectedRangeManager.h"
     15  1.1  joerg 
     16  1.1  joerg #include "FormatToken.h"
     17  1.1  joerg #include "TokenAnnotator.h"
     18  1.1  joerg 
     19  1.1  joerg namespace clang {
     20  1.1  joerg namespace format {
     21  1.1  joerg 
     22  1.1  joerg bool AffectedRangeManager::computeAffectedLines(
     23  1.1  joerg     SmallVectorImpl<AnnotatedLine *> &Lines) {
     24  1.1  joerg   SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin();
     25  1.1  joerg   SmallVectorImpl<AnnotatedLine *>::iterator E = Lines.end();
     26  1.1  joerg   bool SomeLineAffected = false;
     27  1.1  joerg   const AnnotatedLine *PreviousLine = nullptr;
     28  1.1  joerg   while (I != E) {
     29  1.1  joerg     AnnotatedLine *Line = *I;
     30  1.1  joerg     Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
     31  1.1  joerg 
     32  1.1  joerg     // If a line is part of a preprocessor directive, it needs to be formatted
     33  1.1  joerg     // if any token within the directive is affected.
     34  1.1  joerg     if (Line->InPPDirective) {
     35  1.1  joerg       FormatToken *Last = Line->Last;
     36  1.1  joerg       SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
     37  1.1  joerg       while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
     38  1.1  joerg         Last = (*PPEnd)->Last;
     39  1.1  joerg         ++PPEnd;
     40  1.1  joerg       }
     41  1.1  joerg 
     42  1.1  joerg       if (affectsTokenRange(*Line->First, *Last,
     43  1.1  joerg                             /*IncludeLeadingNewlines=*/false)) {
     44  1.1  joerg         SomeLineAffected = true;
     45  1.1  joerg         markAllAsAffected(I, PPEnd);
     46  1.1  joerg       }
     47  1.1  joerg       I = PPEnd;
     48  1.1  joerg       continue;
     49  1.1  joerg     }
     50  1.1  joerg 
     51  1.1  joerg     if (nonPPLineAffected(Line, PreviousLine, Lines))
     52  1.1  joerg       SomeLineAffected = true;
     53  1.1  joerg 
     54  1.1  joerg     PreviousLine = Line;
     55  1.1  joerg     ++I;
     56  1.1  joerg   }
     57  1.1  joerg   return SomeLineAffected;
     58  1.1  joerg }
     59  1.1  joerg 
     60  1.1  joerg bool AffectedRangeManager::affectsCharSourceRange(
     61  1.1  joerg     const CharSourceRange &Range) {
     62  1.1  joerg   for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
     63  1.1  joerg                                                         E = Ranges.end();
     64  1.1  joerg        I != E; ++I) {
     65  1.1  joerg     if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
     66  1.1  joerg         !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
     67  1.1  joerg       return true;
     68  1.1  joerg   }
     69  1.1  joerg   return false;
     70  1.1  joerg }
     71  1.1  joerg 
     72  1.1  joerg bool AffectedRangeManager::affectsTokenRange(const FormatToken &First,
     73  1.1  joerg                                              const FormatToken &Last,
     74  1.1  joerg                                              bool IncludeLeadingNewlines) {
     75  1.1  joerg   SourceLocation Start = First.WhitespaceRange.getBegin();
     76  1.1  joerg   if (!IncludeLeadingNewlines)
     77  1.1  joerg     Start = Start.getLocWithOffset(First.LastNewlineOffset);
     78  1.1  joerg   SourceLocation End = Last.getStartOfNonWhitespace();
     79  1.1  joerg   End = End.getLocWithOffset(Last.TokenText.size());
     80  1.1  joerg   CharSourceRange Range = CharSourceRange::getCharRange(Start, End);
     81  1.1  joerg   return affectsCharSourceRange(Range);
     82  1.1  joerg }
     83  1.1  joerg 
     84  1.1  joerg bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) {
     85  1.1  joerg   CharSourceRange EmptyLineRange = CharSourceRange::getCharRange(
     86  1.1  joerg       Tok.WhitespaceRange.getBegin(),
     87  1.1  joerg       Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));
     88  1.1  joerg   return affectsCharSourceRange(EmptyLineRange);
     89  1.1  joerg }
     90  1.1  joerg 
     91  1.1  joerg void AffectedRangeManager::markAllAsAffected(
     92  1.1  joerg     SmallVectorImpl<AnnotatedLine *>::iterator I,
     93  1.1  joerg     SmallVectorImpl<AnnotatedLine *>::iterator E) {
     94  1.1  joerg   while (I != E) {
     95  1.1  joerg     (*I)->Affected = true;
     96  1.1  joerg     markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
     97  1.1  joerg     ++I;
     98  1.1  joerg   }
     99  1.1  joerg }
    100  1.1  joerg 
    101  1.1  joerg bool AffectedRangeManager::nonPPLineAffected(
    102  1.1  joerg     AnnotatedLine *Line, const AnnotatedLine *PreviousLine,
    103  1.1  joerg     SmallVectorImpl<AnnotatedLine *> &Lines) {
    104  1.1  joerg   bool SomeLineAffected = false;
    105  1.1  joerg   Line->ChildrenAffected = computeAffectedLines(Line->Children);
    106  1.1  joerg   if (Line->ChildrenAffected)
    107  1.1  joerg     SomeLineAffected = true;
    108  1.1  joerg 
    109  1.1  joerg   // Stores whether one of the line's tokens is directly affected.
    110  1.1  joerg   bool SomeTokenAffected = false;
    111  1.1  joerg   // Stores whether we need to look at the leading newlines of the next token
    112  1.1  joerg   // in order to determine whether it was affected.
    113  1.1  joerg   bool IncludeLeadingNewlines = false;
    114  1.1  joerg 
    115  1.1  joerg   // Stores whether the first child line of any of this line's tokens is
    116  1.1  joerg   // affected.
    117  1.1  joerg   bool SomeFirstChildAffected = false;
    118  1.1  joerg 
    119  1.1  joerg   for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
    120  1.1  joerg     // Determine whether 'Tok' was affected.
    121  1.1  joerg     if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
    122  1.1  joerg       SomeTokenAffected = true;
    123  1.1  joerg 
    124  1.1  joerg     // Determine whether the first child of 'Tok' was affected.
    125  1.1  joerg     if (!Tok->Children.empty() && Tok->Children.front()->Affected)
    126  1.1  joerg       SomeFirstChildAffected = true;
    127  1.1  joerg 
    128  1.1  joerg     IncludeLeadingNewlines = Tok->Children.empty();
    129  1.1  joerg   }
    130  1.1  joerg 
    131  1.1  joerg   // Was this line moved, i.e. has it previously been on the same line as an
    132  1.1  joerg   // affected line?
    133  1.1  joerg   bool LineMoved = PreviousLine && PreviousLine->Affected &&
    134  1.1  joerg                    Line->First->NewlinesBefore == 0;
    135  1.1  joerg 
    136  1.1  joerg   bool IsContinuedComment =
    137  1.1  joerg       Line->First->is(tok::comment) && Line->First->Next == nullptr &&
    138  1.1  joerg       Line->First->NewlinesBefore < 2 && PreviousLine &&
    139  1.1  joerg       PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
    140  1.1  joerg 
    141  1.1  joerg   bool IsAffectedClosingBrace =
    142  1.1  joerg       Line->First->is(tok::r_brace) &&
    143  1.1  joerg       Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex &&
    144  1.1  joerg       Lines[Line->MatchingOpeningBlockLineIndex]->Affected;
    145  1.1  joerg 
    146  1.1  joerg   if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
    147  1.1  joerg       IsContinuedComment || IsAffectedClosingBrace) {
    148  1.1  joerg     Line->Affected = true;
    149  1.1  joerg     SomeLineAffected = true;
    150  1.1  joerg   }
    151  1.1  joerg   return SomeLineAffected;
    152  1.1  joerg }
    153  1.1  joerg 
    154  1.1  joerg } // namespace format
    155  1.1  joerg } // namespace clang
    156