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