xref: /openbsd-src/gnu/llvm/clang/lib/Format/AffectedRangeManager.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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