AffectedRangeManager.cpp revision 304241
1//===--- AffectedRangeManager.cpp - Format C++ code -----------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file implements AffectRangeManager class.
12///
13//===----------------------------------------------------------------------===//
14
15#include "AffectedRangeManager.h"
16
17#include "FormatToken.h"
18#include "TokenAnnotator.h"
19
20namespace clang {
21namespace format {
22
23bool AffectedRangeManager::computeAffectedLines(
24    SmallVectorImpl<AnnotatedLine *>::iterator I,
25    SmallVectorImpl<AnnotatedLine *>::iterator E) {
26  bool SomeLineAffected = false;
27  const AnnotatedLine *PreviousLine = nullptr;
28  while (I != E) {
29    AnnotatedLine *Line = *I;
30    Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
31
32    // If a line is part of a preprocessor directive, it needs to be formatted
33    // if any token within the directive is affected.
34    if (Line->InPPDirective) {
35      FormatToken *Last = Line->Last;
36      SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
37      while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
38        Last = (*PPEnd)->Last;
39        ++PPEnd;
40      }
41
42      if (affectsTokenRange(*Line->First, *Last,
43                            /*IncludeLeadingNewlines=*/false)) {
44        SomeLineAffected = true;
45        markAllAsAffected(I, PPEnd);
46      }
47      I = PPEnd;
48      continue;
49    }
50
51    if (nonPPLineAffected(Line, PreviousLine))
52      SomeLineAffected = true;
53
54    PreviousLine = Line;
55    ++I;
56  }
57  return SomeLineAffected;
58}
59
60bool AffectedRangeManager::affectsCharSourceRange(
61    const CharSourceRange &Range) {
62  for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
63                                                        E = Ranges.end();
64       I != E; ++I) {
65    if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
66        !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
67      return true;
68  }
69  return false;
70}
71
72bool 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
84bool 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
91void 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
101bool AffectedRangeManager::nonPPLineAffected(
102    AnnotatedLine *Line, const AnnotatedLine *PreviousLine) {
103  bool SomeLineAffected = false;
104  Line->ChildrenAffected =
105      computeAffectedLines(Line->Children.begin(), Line->Children.end());
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  for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
120    // Determine whether 'Tok' was affected.
121    if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
122      SomeTokenAffected = true;
123
124    // Determine whether the first child of 'Tok' was affected.
125    if (!Tok->Children.empty() && Tok->Children.front()->Affected)
126      SomeFirstChildAffected = true;
127
128    IncludeLeadingNewlines = Tok->Children.empty();
129  }
130
131  // Was this line moved, i.e. has it previously been on the same line as an
132  // affected line?
133  bool LineMoved = PreviousLine && PreviousLine->Affected &&
134                   Line->First->NewlinesBefore == 0;
135
136  bool IsContinuedComment =
137      Line->First->is(tok::comment) && Line->First->Next == nullptr &&
138      Line->First->NewlinesBefore < 2 && PreviousLine &&
139      PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
140
141  if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
142      IsContinuedComment) {
143    Line->Affected = true;
144    SomeLineAffected = true;
145  }
146  return SomeLineAffected;
147}
148
149} // namespace format
150} // namespace clang
151