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