14cfb88a9SEric Liu //===--- AffectedRangeManager.cpp - Format C++ code -----------------------===//
24cfb88a9SEric Liu //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64cfb88a9SEric Liu //
74cfb88a9SEric Liu //===----------------------------------------------------------------------===//
84cfb88a9SEric Liu ///
94cfb88a9SEric Liu /// \file
109fc8faf9SAdrian Prantl /// This file implements AffectRangeManager class.
114cfb88a9SEric Liu ///
124cfb88a9SEric Liu //===----------------------------------------------------------------------===//
134cfb88a9SEric Liu 
144cfb88a9SEric Liu #include "AffectedRangeManager.h"
154cfb88a9SEric Liu 
164cfb88a9SEric Liu #include "FormatToken.h"
174cfb88a9SEric Liu #include "TokenAnnotator.h"
184cfb88a9SEric Liu 
194cfb88a9SEric Liu namespace clang {
204cfb88a9SEric Liu namespace format {
214cfb88a9SEric Liu 
computeAffectedLines(SmallVectorImpl<AnnotatedLine * > & Lines)224cfb88a9SEric Liu bool AffectedRangeManager::computeAffectedLines(
230dddcf78SManuel Klimek     SmallVectorImpl<AnnotatedLine *> &Lines) {
240dddcf78SManuel Klimek   SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin();
250dddcf78SManuel Klimek   SmallVectorImpl<AnnotatedLine *>::iterator E = Lines.end();
264cfb88a9SEric Liu   bool SomeLineAffected = false;
274cfb88a9SEric Liu   const AnnotatedLine *PreviousLine = nullptr;
284cfb88a9SEric Liu   while (I != E) {
294cfb88a9SEric Liu     AnnotatedLine *Line = *I;
30670a721dSMarek Kurdej     assert(Line->First);
314cfb88a9SEric Liu     Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
324cfb88a9SEric Liu 
334cfb88a9SEric Liu     // If a line is part of a preprocessor directive, it needs to be formatted
344cfb88a9SEric Liu     // if any token within the directive is affected.
354cfb88a9SEric Liu     if (Line->InPPDirective) {
364cfb88a9SEric Liu       FormatToken *Last = Line->Last;
374cfb88a9SEric Liu       SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
384cfb88a9SEric Liu       while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
394cfb88a9SEric Liu         Last = (*PPEnd)->Last;
404cfb88a9SEric Liu         ++PPEnd;
414cfb88a9SEric Liu       }
424cfb88a9SEric Liu 
434cfb88a9SEric Liu       if (affectsTokenRange(*Line->First, *Last,
444cfb88a9SEric Liu                             /*IncludeLeadingNewlines=*/false)) {
454cfb88a9SEric Liu         SomeLineAffected = true;
464cfb88a9SEric Liu         markAllAsAffected(I, PPEnd);
474cfb88a9SEric Liu       }
484cfb88a9SEric Liu       I = PPEnd;
494cfb88a9SEric Liu       continue;
504cfb88a9SEric Liu     }
514cfb88a9SEric Liu 
520dddcf78SManuel Klimek     if (nonPPLineAffected(Line, PreviousLine, Lines))
534cfb88a9SEric Liu       SomeLineAffected = true;
544cfb88a9SEric Liu 
554cfb88a9SEric Liu     PreviousLine = Line;
564cfb88a9SEric Liu     ++I;
574cfb88a9SEric Liu   }
584cfb88a9SEric Liu   return SomeLineAffected;
594cfb88a9SEric Liu }
604cfb88a9SEric Liu 
affectsCharSourceRange(const CharSourceRange & Range)614cfb88a9SEric Liu bool AffectedRangeManager::affectsCharSourceRange(
624cfb88a9SEric Liu     const CharSourceRange &Range) {
63*bebf7bdfSowenca   for (const CharSourceRange &R : Ranges) {
6401f355feSMarek Kurdej     if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), R.getBegin()) &&
65*bebf7bdfSowenca         !SourceMgr.isBeforeInTranslationUnit(R.getEnd(), Range.getBegin())) {
664cfb88a9SEric Liu       return true;
67*bebf7bdfSowenca     }
68*bebf7bdfSowenca   }
694cfb88a9SEric Liu   return false;
704cfb88a9SEric Liu }
714cfb88a9SEric Liu 
affectsTokenRange(const FormatToken & First,const FormatToken & Last,bool IncludeLeadingNewlines)724cfb88a9SEric Liu bool AffectedRangeManager::affectsTokenRange(const FormatToken &First,
734cfb88a9SEric Liu                                              const FormatToken &Last,
744cfb88a9SEric Liu                                              bool IncludeLeadingNewlines) {
754cfb88a9SEric Liu   SourceLocation Start = First.WhitespaceRange.getBegin();
764cfb88a9SEric Liu   if (!IncludeLeadingNewlines)
774cfb88a9SEric Liu     Start = Start.getLocWithOffset(First.LastNewlineOffset);
784cfb88a9SEric Liu   SourceLocation End = Last.getStartOfNonWhitespace();
794cfb88a9SEric Liu   End = End.getLocWithOffset(Last.TokenText.size());
804cfb88a9SEric Liu   CharSourceRange Range = CharSourceRange::getCharRange(Start, End);
814cfb88a9SEric Liu   return affectsCharSourceRange(Range);
824cfb88a9SEric Liu }
834cfb88a9SEric Liu 
affectsLeadingEmptyLines(const FormatToken & Tok)844cfb88a9SEric Liu bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) {
854cfb88a9SEric Liu   CharSourceRange EmptyLineRange = CharSourceRange::getCharRange(
864cfb88a9SEric Liu       Tok.WhitespaceRange.getBegin(),
874cfb88a9SEric Liu       Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));
884cfb88a9SEric Liu   return affectsCharSourceRange(EmptyLineRange);
894cfb88a9SEric Liu }
904cfb88a9SEric Liu 
markAllAsAffected(SmallVectorImpl<AnnotatedLine * >::iterator I,SmallVectorImpl<AnnotatedLine * >::iterator E)914cfb88a9SEric Liu void AffectedRangeManager::markAllAsAffected(
924cfb88a9SEric Liu     SmallVectorImpl<AnnotatedLine *>::iterator I,
934cfb88a9SEric Liu     SmallVectorImpl<AnnotatedLine *>::iterator E) {
944cfb88a9SEric Liu   while (I != E) {
954cfb88a9SEric Liu     (*I)->Affected = true;
964cfb88a9SEric Liu     markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
974cfb88a9SEric Liu     ++I;
984cfb88a9SEric Liu   }
994cfb88a9SEric Liu }
1004cfb88a9SEric Liu 
nonPPLineAffected(AnnotatedLine * Line,const AnnotatedLine * PreviousLine,SmallVectorImpl<AnnotatedLine * > & Lines)1014cfb88a9SEric Liu bool AffectedRangeManager::nonPPLineAffected(
1020dddcf78SManuel Klimek     AnnotatedLine *Line, const AnnotatedLine *PreviousLine,
1030dddcf78SManuel Klimek     SmallVectorImpl<AnnotatedLine *> &Lines) {
1044cfb88a9SEric Liu   bool SomeLineAffected = false;
1050dddcf78SManuel Klimek   Line->ChildrenAffected = computeAffectedLines(Line->Children);
1064cfb88a9SEric Liu   if (Line->ChildrenAffected)
1074cfb88a9SEric Liu     SomeLineAffected = true;
1084cfb88a9SEric Liu 
1094cfb88a9SEric Liu   // Stores whether one of the line's tokens is directly affected.
1104cfb88a9SEric Liu   bool SomeTokenAffected = false;
1114cfb88a9SEric Liu   // Stores whether we need to look at the leading newlines of the next token
1124cfb88a9SEric Liu   // in order to determine whether it was affected.
1134cfb88a9SEric Liu   bool IncludeLeadingNewlines = false;
1144cfb88a9SEric Liu 
1154cfb88a9SEric Liu   // Stores whether the first child line of any of this line's tokens is
1164cfb88a9SEric Liu   // affected.
1174cfb88a9SEric Liu   bool SomeFirstChildAffected = false;
1184cfb88a9SEric Liu 
119670a721dSMarek Kurdej   assert(Line->First);
1204cfb88a9SEric Liu   for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
1214cfb88a9SEric Liu     // Determine whether 'Tok' was affected.
1224cfb88a9SEric Liu     if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
1234cfb88a9SEric Liu       SomeTokenAffected = true;
1244cfb88a9SEric Liu 
1254cfb88a9SEric Liu     // Determine whether the first child of 'Tok' was affected.
1264cfb88a9SEric Liu     if (!Tok->Children.empty() && Tok->Children.front()->Affected)
1274cfb88a9SEric Liu       SomeFirstChildAffected = true;
1284cfb88a9SEric Liu 
1294cfb88a9SEric Liu     IncludeLeadingNewlines = Tok->Children.empty();
1304cfb88a9SEric Liu   }
1314cfb88a9SEric Liu 
1324cfb88a9SEric Liu   // Was this line moved, i.e. has it previously been on the same line as an
1334cfb88a9SEric Liu   // affected line?
1344cfb88a9SEric Liu   bool LineMoved = PreviousLine && PreviousLine->Affected &&
1354cfb88a9SEric Liu                    Line->First->NewlinesBefore == 0;
1364cfb88a9SEric Liu 
1374cfb88a9SEric Liu   bool IsContinuedComment =
1384cfb88a9SEric Liu       Line->First->is(tok::comment) && Line->First->Next == nullptr &&
1394cfb88a9SEric Liu       Line->First->NewlinesBefore < 2 && PreviousLine &&
1404cfb88a9SEric Liu       PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
1414cfb88a9SEric Liu 
1420dddcf78SManuel Klimek   bool IsAffectedClosingBrace =
1430dddcf78SManuel Klimek       Line->First->is(tok::r_brace) &&
1440dddcf78SManuel Klimek       Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex &&
1450dddcf78SManuel Klimek       Lines[Line->MatchingOpeningBlockLineIndex]->Affected;
1460dddcf78SManuel Klimek 
1474cfb88a9SEric Liu   if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
1480dddcf78SManuel Klimek       IsContinuedComment || IsAffectedClosingBrace) {
1494cfb88a9SEric Liu     Line->Affected = true;
1504cfb88a9SEric Liu     SomeLineAffected = true;
1514cfb88a9SEric Liu   }
1524cfb88a9SEric Liu   return SomeLineAffected;
1534cfb88a9SEric Liu }
1544cfb88a9SEric Liu 
1554cfb88a9SEric Liu } // namespace format
1564cfb88a9SEric Liu } // namespace clang
157