AffectedRangeManager.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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. Line->LeadingEmptyLinesAffected = affectsLeadingEmptyLines(*Line->First);
  27. // If a line is part of a preprocessor directive, it needs to be formatted
  28. // if any token within the directive is affected.
  29. if (Line->InPPDirective) {
  30. FormatToken *Last = Line->Last;
  31. SmallVectorImpl<AnnotatedLine *>::iterator PPEnd = I + 1;
  32. while (PPEnd != E && !(*PPEnd)->First->HasUnescapedNewline) {
  33. Last = (*PPEnd)->Last;
  34. ++PPEnd;
  35. }
  36. if (affectsTokenRange(*Line->First, *Last,
  37. /*IncludeLeadingNewlines=*/false)) {
  38. SomeLineAffected = true;
  39. markAllAsAffected(I, PPEnd);
  40. }
  41. I = PPEnd;
  42. continue;
  43. }
  44. if (nonPPLineAffected(Line, PreviousLine, Lines))
  45. SomeLineAffected = true;
  46. PreviousLine = Line;
  47. ++I;
  48. }
  49. return SomeLineAffected;
  50. }
  51. bool AffectedRangeManager::affectsCharSourceRange(
  52. const CharSourceRange &Range) {
  53. for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
  54. E = Ranges.end();
  55. I != E; ++I) {
  56. if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), I->getBegin()) &&
  57. !SourceMgr.isBeforeInTranslationUnit(I->getEnd(), Range.getBegin()))
  58. return true;
  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. for (FormatToken *Tok = Line->First; Tok; Tok = Tok->Next) {
  104. // Determine whether 'Tok' was affected.
  105. if (affectsTokenRange(*Tok, *Tok, IncludeLeadingNewlines))
  106. SomeTokenAffected = true;
  107. // Determine whether the first child of 'Tok' was affected.
  108. if (!Tok->Children.empty() && Tok->Children.front()->Affected)
  109. SomeFirstChildAffected = true;
  110. IncludeLeadingNewlines = Tok->Children.empty();
  111. }
  112. // Was this line moved, i.e. has it previously been on the same line as an
  113. // affected line?
  114. bool LineMoved = PreviousLine && PreviousLine->Affected &&
  115. Line->First->NewlinesBefore == 0;
  116. bool IsContinuedComment =
  117. Line->First->is(tok::comment) && Line->First->Next == nullptr &&
  118. Line->First->NewlinesBefore < 2 && PreviousLine &&
  119. PreviousLine->Affected && PreviousLine->Last->is(tok::comment);
  120. bool IsAffectedClosingBrace =
  121. Line->First->is(tok::r_brace) &&
  122. Line->MatchingOpeningBlockLineIndex != UnwrappedLine::kInvalidIndex &&
  123. Lines[Line->MatchingOpeningBlockLineIndex]->Affected;
  124. if (SomeTokenAffected || SomeFirstChildAffected || LineMoved ||
  125. IsContinuedComment || IsAffectedClosingBrace) {
  126. Line->Affected = true;
  127. SomeLineAffected = true;
  128. }
  129. return SomeLineAffected;
  130. }
  131. } // namespace format
  132. } // namespace clang