AffectedRangeManager.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. }
  59. }
  60. return false;
  61. }
  62. bool AffectedRangeManager::affectsTokenRange(const FormatToken &First,
  63. const FormatToken &Last,
  64. bool IncludeLeadingNewlines) {
  65. SourceLocation Start = First.WhitespaceRange.getBegin();
  66. if (!IncludeLeadingNewlines)
  67. Start = Start.getLocWithOffset(First.LastNewlineOffset);
  68. SourceLocation End = Last.getStartOfNonWhitespace();
  69. End = End.getLocWithOffset(Last.TokenText.size());
  70. CharSourceRange Range = CharSourceRange::getCharRange(Start, End);
  71. return affectsCharSourceRange(Range);
  72. }
  73. bool AffectedRangeManager::affectsLeadingEmptyLines(const FormatToken &Tok) {
  74. CharSourceRange EmptyLineRange = CharSourceRange::getCharRange(
  75. Tok.WhitespaceRange.getBegin(),
  76. Tok.WhitespaceRange.getBegin().getLocWithOffset(Tok.LastNewlineOffset));
  77. return affectsCharSourceRange(EmptyLineRange);
  78. }
  79. void AffectedRangeManager::markAllAsAffected(
  80. SmallVectorImpl<AnnotatedLine *>::iterator I,
  81. SmallVectorImpl<AnnotatedLine *>::iterator E) {
  82. while (I != E) {
  83. (*I)->Affected = true;
  84. markAllAsAffected((*I)->Children.begin(), (*I)->Children.end());
  85. ++I;
  86. }
  87. }
  88. bool AffectedRangeManager::nonPPLineAffected(
  89. AnnotatedLine *Line, const AnnotatedLine *PreviousLine,
  90. SmallVectorImpl<AnnotatedLine *> &Lines) {
  91. bool SomeLineAffected = false;
  92. Line->ChildrenAffected = computeAffectedLines(Line->Children);
  93. if (Line->ChildrenAffected)
  94. SomeLineAffected = true;
  95. // Stores whether one of the line's tokens is directly affected.
  96. bool SomeTokenAffected = false;
  97. // Stores whether we need to look at the leading newlines of the next token
  98. // in order to determine whether it was affected.
  99. bool IncludeLeadingNewlines = false;
  100. // Stores whether the first child line of any of this line's tokens is
  101. // affected.
  102. bool SomeFirstChildAffected = false;
  103. assert(Line->First);
  104. for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
  105. // Determine whether 'Tok' was affected.
  106. if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
  107. SomeTokenAffected = true;
  108. // Determine whether the first child of 'Tok' was affected.
  109. if (!Tok->Children.empty() && Tok->Children.front()->Affected)
  110. SomeFirstChildAffected = true;
  111. IncludeLeadingNewlines = Tok->Children.empty();
  112. }
  113. // Was this line moved, i.e. has it previously been on the same line as an
  114. // affected line?
  115. bool LineMoved = PreviousLine && PreviousLine->Affected &&
  116. Line->First->NewlinesBefore == 0;
  117. bool IsContinuedComment =
  118. Line->First->is(tok::comment) && Line->First->Next == nullptr &&
  119. Line->First->NewlinesBefore < 2 && PreviousLine &&
  120. PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
  121. bool IsAffectedClosingBrace =
  122. Line->First->is(tok::r_brace) &&
  123. Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex &&
  124. Lines[Line->MatchingOpeningBlockLineIndex]->Affected;
  125. if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
  126. IsContinuedComment || IsAffectedClosingBrace) {
  127. Line->Affected = true;
  128. SomeLineAffected = true;
  129. }
  130. return SomeLineAffected;
  131. }
  132. } // namespace format
  133. } // namespace clang