AffectedRangeManager.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. #include "AffectedRangeManager.h"
  14. #include "FormatToken.h"
  15. #include "TokenAnnotator.h"
  16. namespace clang {
  17. namespace format {
  18. bool AffectedRangeManager::computeAffectedLines(
  19. SmallVectorImpl<AnnotatedLine *> &Lines) {
  20. SmallVectorImpl<AnnotatedLine *>::iterator I = Lines.begin();
  21. SmallVectorImpl<AnnotatedLine *>::iterator E = Lines.end();
  22. bool SomeLineAffected = false;
  23. const AnnotatedLine *PreviousLine = nullptr;
  24. while (I != E) {
  25. AnnotatedLine *Line = *I;
  26. assert(Line->First);
  27. Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
  28. // If a line is part of a preprocessor directive, it needs to be formatted
  29. // if any token within the directive is affected.
  30. if (Line->InPPDirective) {
  31. FormatToken *Last = Line->Last;
  32. SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
  33. while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
  34. Last = (*PPEnd)->Last;
  35. ++PPEnd;
  36. }
  37. if (affectsTokenRange(*Line->First, *Last,
  38. /*IncludeLeadingNewlines=*/false)) {
  39. SomeLineAffected = true;
  40. markAllAsAffected(I, PPEnd);
  41. }
  42. I = PPEnd;
  43. continue;
  44. }
  45. if (nonPPLineAffected(Line, PreviousLine, Lines))
  46. SomeLineAffected = true;
  47. PreviousLine = Line;
  48. ++I;
  49. }
  50. return SomeLineAffected;
  51. }
  52. bool AffectedRangeManager::affectsCharSourceRange(
  53. const CharSourceRange &Range) {
  54. for (const CharSourceRange &R : Ranges)
  55. if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), R.getBegin()) &&
  56. !SourceMgr.isBeforeInTranslationUnit(R.getEnd(), Range.getBegin()))
  57. return true;
  58. return false;
  59. }
  60. bool AffectedRangeManager::affectsTokenRange(const FormatToken &First,
  61. const FormatToken &Last,
  62. bool IncludeLeadingNewlines) {
  63. SourceLocation Start = First.WhitespaceRange.getBegin();
  64. if (!IncludeLeadingNewlines)
  65. Start = Start.getLocWithOffset(First.LastNewlineOffset);
  66. SourceLocation End = Last.getStartOfNonWhitespace();
  67. End = End.getLocWithOffset(Last.TokenText.size());
  68. CharSourceRange Range = CharSourceRange::getCharRange(Start, End);
  69. return affectsCharSourceRange(Range);
  70. }
  71. bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) {
  72. CharSourceRange EmptyLineRange = CharSourceRange::getCharRange(
  73. Tok.WhitespaceRange.getBegin(),
  74. Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));
  75. return affectsCharSourceRange(EmptyLineRange);
  76. }
  77. void AffectedRangeManager::markAllAsAffected(
  78. SmallVectorImpl<AnnotatedLine *>::iterator I,
  79. SmallVectorImpl<AnnotatedLine *>::iterator E) {
  80. while (I != E) {
  81. (*I)->Affected = true;
  82. markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
  83. ++I;
  84. }
  85. }
  86. bool AffectedRangeManager::nonPPLineAffected(
  87. AnnotatedLine *Line, const AnnotatedLine *PreviousLine,
  88. SmallVectorImpl<AnnotatedLine *> &Lines) {
  89. bool SomeLineAffected = false;
  90. Line->ChildrenAffected = computeAffectedLines(Line->Children);
  91. if (Line->ChildrenAffected)
  92. SomeLineAffected = true;
  93. // Stores whether one of the line's tokens is directly affected.
  94. bool SomeTokenAffected = false;
  95. // Stores whether we need to look at the leading newlines of the next token
  96. // in order to determine whether it was affected.
  97. bool IncludeLeadingNewlines = false;
  98. // Stores whether the first child line of any of this line's tokens is
  99. // affected.
  100. bool SomeFirstChildAffected = false;
  101. assert(Line->First);
  102. for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
  103. // Determine whether 'Tok' was affected.
  104. if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
  105. SomeTokenAffected = true;
  106. // Determine whether the first child of 'Tok' was affected.
  107. if (!Tok->Children.empty() && Tok->Children.front()->Affected)
  108. SomeFirstChildAffected = true;
  109. IncludeLeadingNewlines = Tok->Children.empty();
  110. }
  111. // Was this line moved, i.e. has it previously been on the same line as an
  112. // affected line?
  113. bool LineMoved = PreviousLine && PreviousLine->Affected &&
  114. Line->First->NewlinesBefore == 0;
  115. bool IsContinuedComment =
  116. Line->First->is(tok::comment) && Line->First->Next == nullptr &&
  117. Line->First->NewlinesBefore < 2 && PreviousLine &&
  118. PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
  119. bool IsAffectedClosingBrace =
  120. Line->First->is(tok::r_brace) &&
  121. Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex &&
  122. Lines[Line->MatchingOpeningBlockLineIndex]->Affected;
  123. if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
  124. IsContinuedComment || IsAffectedClosingBrace) {
  125. Line->Affected = true;
  126. SomeLineAffected = true;
  127. }
  128. return SomeLineAffected;
  129. }
  130. } // namespace format
  131. } // namespace clang