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