xref: /freebsd-src/contrib/llvm-project/clang/lib/Format/AffectedRangeManager.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===--- AffectedRangeManager.cpp - Format C++ code -----------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements AffectRangeManager class.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "AffectedRangeManager.h"
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "FormatToken.h"
170b57cec5SDimitry Andric #include "TokenAnnotator.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace clang {
200b57cec5SDimitry Andric namespace format {
210b57cec5SDimitry Andric 
computeAffectedLines(SmallVectorImpl<AnnotatedLine * > & Lines)220b57cec5SDimitry Andric bool AffectedRangeManager::computeAffectedLines(
230b57cec5SDimitry Andric     SmallVectorImpl<AnnotatedLine *> &Lines) {
240b57cec5SDimitry Andric   SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin();
250b57cec5SDimitry Andric   SmallVectorImpl<AnnotatedLine *>::iterator E = Lines.end();
260b57cec5SDimitry Andric   bool SomeLineAffected = false;
270b57cec5SDimitry Andric   const AnnotatedLine *PreviousLine = nullptr;
280b57cec5SDimitry Andric   while (I != E) {
290b57cec5SDimitry Andric     AnnotatedLine *Line = *I;
3004eeddc0SDimitry Andric     assert(Line->First);
310b57cec5SDimitry Andric     Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric     // If a line is part of a preprocessor directive, it needs to be formatted
340b57cec5SDimitry Andric     // if any token within the directive is affected.
350b57cec5SDimitry Andric     if (Line->InPPDirective) {
360b57cec5SDimitry Andric       FormatToken *Last = Line->Last;
370b57cec5SDimitry Andric       SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
380b57cec5SDimitry Andric       while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
390b57cec5SDimitry Andric         Last = (*PPEnd)->Last;
400b57cec5SDimitry Andric         ++PPEnd;
410b57cec5SDimitry Andric       }
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric       if (affectsTokenRange(*Line->First, *Last,
440b57cec5SDimitry Andric                             /*IncludeLeadingNewlines=*/false)) {
450b57cec5SDimitry Andric         SomeLineAffected = true;
460b57cec5SDimitry Andric         markAllAsAffected(I, PPEnd);
470b57cec5SDimitry Andric       }
480b57cec5SDimitry Andric       I = PPEnd;
490b57cec5SDimitry Andric       continue;
500b57cec5SDimitry Andric     }
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric     if (nonPPLineAffected(Line, PreviousLine, Lines))
530b57cec5SDimitry Andric       SomeLineAffected = true;
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric     PreviousLine = Line;
560b57cec5SDimitry Andric     ++I;
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric   return SomeLineAffected;
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric 
affectsCharSourceRange(const CharSourceRange & Range)610b57cec5SDimitry Andric bool AffectedRangeManager::affectsCharSourceRange(
620b57cec5SDimitry Andric     const CharSourceRange &Range) {
6381ad6265SDimitry Andric   for (const CharSourceRange &R : Ranges) {
6404eeddc0SDimitry Andric     if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), R.getBegin()) &&
6581ad6265SDimitry Andric         !SourceMgr.isBeforeInTranslationUnit(R.getEnd(), Range.getBegin())) {
660b57cec5SDimitry Andric       return true;
6781ad6265SDimitry Andric     }
6881ad6265SDimitry Andric   }
690b57cec5SDimitry Andric   return false;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
affectsTokenRange(const FormatToken & First,const FormatToken & Last,bool IncludeLeadingNewlines)720b57cec5SDimitry Andric bool AffectedRangeManager::affectsTokenRange(const FormatToken &First,
730b57cec5SDimitry Andric                                              const FormatToken &Last,
740b57cec5SDimitry Andric                                              bool IncludeLeadingNewlines) {
750b57cec5SDimitry Andric   SourceLocation Start = First.WhitespaceRange.getBegin();
760b57cec5SDimitry Andric   if (!IncludeLeadingNewlines)
770b57cec5SDimitry Andric     Start = Start.getLocWithOffset(First.LastNewlineOffset);
780b57cec5SDimitry Andric   SourceLocation End = Last.getStartOfNonWhitespace();
790b57cec5SDimitry Andric   End = End.getLocWithOffset(Last.TokenText.size());
800b57cec5SDimitry Andric   CharSourceRange Range = CharSourceRange::getCharRange(Start, End);
810b57cec5SDimitry Andric   return affectsCharSourceRange(Range);
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
affectsLeadingEmptyLines(const FormatToken & Tok)840b57cec5SDimitry Andric bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) {
850b57cec5SDimitry Andric   CharSourceRange EmptyLineRange = CharSourceRange::getCharRange(
860b57cec5SDimitry Andric       Tok.WhitespaceRange.getBegin(),
870b57cec5SDimitry Andric       Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));
880b57cec5SDimitry Andric   return affectsCharSourceRange(EmptyLineRange);
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
markAllAsAffected(SmallVectorImpl<AnnotatedLine * >::iterator I,SmallVectorImpl<AnnotatedLine * >::iterator E)910b57cec5SDimitry Andric void AffectedRangeManager::markAllAsAffected(
920b57cec5SDimitry Andric     SmallVectorImpl<AnnotatedLine *>::iterator I,
930b57cec5SDimitry Andric     SmallVectorImpl<AnnotatedLine *>::iterator E) {
940b57cec5SDimitry Andric   while (I != E) {
950b57cec5SDimitry Andric     (*I)->Affected = true;
960b57cec5SDimitry Andric     markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
970b57cec5SDimitry Andric     ++I;
980b57cec5SDimitry Andric   }
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
nonPPLineAffected(AnnotatedLine * Line,const AnnotatedLine * PreviousLine,SmallVectorImpl<AnnotatedLine * > & Lines)1010b57cec5SDimitry Andric bool AffectedRangeManager::nonPPLineAffected(
1020b57cec5SDimitry Andric     AnnotatedLine *Line, const AnnotatedLine *PreviousLine,
1030b57cec5SDimitry Andric     SmallVectorImpl<AnnotatedLine *> &Lines) {
1040b57cec5SDimitry Andric   bool SomeLineAffected = false;
1050b57cec5SDimitry Andric   Line->ChildrenAffected = computeAffectedLines(Line->Children);
1060b57cec5SDimitry Andric   if (Line->ChildrenAffected)
1070b57cec5SDimitry Andric     SomeLineAffected = true;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   // Stores whether one of the line's tokens is directly affected.
1100b57cec5SDimitry Andric   bool SomeTokenAffected = false;
1110b57cec5SDimitry Andric   // Stores whether we need to look at the leading newlines of the next token
1120b57cec5SDimitry Andric   // in order to determine whether it was affected.
1130b57cec5SDimitry Andric   bool IncludeLeadingNewlines = false;
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   // Stores whether the first child line of any of this line's tokens is
1160b57cec5SDimitry Andric   // affected.
1170b57cec5SDimitry Andric   bool SomeFirstChildAffected = false;
1180b57cec5SDimitry Andric 
11904eeddc0SDimitry Andric   assert(Line->First);
1200b57cec5SDimitry Andric   for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
1210b57cec5SDimitry Andric     // Determine whether 'Tok' was affected.
1220b57cec5SDimitry Andric     if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
1230b57cec5SDimitry Andric       SomeTokenAffected = true;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric     // Determine whether the first child of 'Tok' was affected.
1260b57cec5SDimitry Andric     if (!Tok->Children.empty() && Tok->Children.front()->Affected)
1270b57cec5SDimitry Andric       SomeFirstChildAffected = true;
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric     IncludeLeadingNewlines = Tok->Children.empty();
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   // Was this line moved, i.e. has it previously been on the same line as an
1330b57cec5SDimitry Andric   // affected line?
1340b57cec5SDimitry Andric   bool LineMoved = PreviousLine && PreviousLine->Affected &&
1350b57cec5SDimitry Andric                    Line->First->NewlinesBefore == 0;
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   bool IsContinuedComment =
138*06c3fb27SDimitry Andric       Line->First->is(tok::comment) && !Line->First->Next &&
1390b57cec5SDimitry Andric       Line->First->NewlinesBefore < 2 && PreviousLine &&
1400b57cec5SDimitry Andric       PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   bool IsAffectedClosingBrace =
1430b57cec5SDimitry Andric       Line->First->is(tok::r_brace) &&
1440b57cec5SDimitry Andric       Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex &&
1450b57cec5SDimitry Andric       Lines[Line->MatchingOpeningBlockLineIndex]->Affected;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
1480b57cec5SDimitry Andric       IsContinuedComment || IsAffectedClosingBrace) {
1490b57cec5SDimitry Andric     Line->Affected = true;
1500b57cec5SDimitry Andric     SomeLineAffected = true;
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric   return SomeLineAffected;
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric } // namespace format
1560b57cec5SDimitry Andric } // namespace clang
157