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