WhitespaceManager.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. //===--- WhitespaceManager.h - Format C++ code ------------------*- C++ -*-===//
  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 WhitespaceManager class manages whitespace around tokens and their
  12. /// replacements.
  13. ///
  14. //===----------------------------------------------------------------------===//
  15. #ifndef LLVM_CLANG_LIB_FORMAT_WHITESPACEMANAGER_H
  16. #define LLVM_CLANG_LIB_FORMAT_WHITESPACEMANAGER_H
  17. #include "TokenAnnotator.h"
  18. #include "clang/Basic/SourceManager.h"
  19. #include "clang/Format/Format.h"
  20. #include <string>
  21. namespace clang {
  22. namespace format {
  23. /// \brief Manages the whitespaces around tokens and their replacements.
  24. ///
  25. /// This includes special handling for certain constructs, e.g. the alignment of
  26. /// trailing line comments.
  27. ///
  28. /// To guarantee correctness of alignment operations, the \c WhitespaceManager
  29. /// must be informed about every token in the source file; for each token, there
  30. /// must be exactly one call to either \c replaceWhitespace or
  31. /// \c addUntouchableToken.
  32. ///
  33. /// There may be multiple calls to \c breakToken for a given token.
  34. class WhitespaceManager {
  35. public:
  36. WhitespaceManager(SourceManager &SourceMgr, const FormatStyle &Style,
  37. bool UseCRLF)
  38. : SourceMgr(SourceMgr), Style(Style), UseCRLF(UseCRLF) {}
  39. /// \brief Prepares the \c WhitespaceManager for another run.
  40. void reset();
  41. /// \brief Replaces the whitespace in front of \p Tok. Only call once for
  42. /// each \c AnnotatedToken.
  43. void replaceWhitespace(FormatToken &Tok, unsigned Newlines,
  44. unsigned IndentLevel, unsigned Spaces,
  45. unsigned StartOfTokenColumn,
  46. bool InPPDirective = false);
  47. /// \brief Adds information about an unchangeable token's whitespace.
  48. ///
  49. /// Needs to be called for every token for which \c replaceWhitespace
  50. /// was not called.
  51. void addUntouchableToken(const FormatToken &Tok, bool InPPDirective);
  52. /// \brief Inserts or replaces whitespace in the middle of a token.
  53. ///
  54. /// Inserts \p PreviousPostfix, \p Newlines, \p Spaces and \p CurrentPrefix
  55. /// (in this order) at \p Offset inside \p Tok, replacing \p ReplaceChars
  56. /// characters.
  57. ///
  58. /// Note: \p Spaces can be negative to retain information about initial
  59. /// relative column offset between a line of a block comment and the start of
  60. /// the comment. This negative offset may be compensated by trailing comment
  61. /// alignment here. In all other cases negative \p Spaces will be truncated to
  62. /// 0.
  63. ///
  64. /// When \p InPPDirective is true, escaped newlines are inserted. \p Spaces is
  65. /// used to align backslashes correctly.
  66. void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset,
  67. unsigned ReplaceChars,
  68. StringRef PreviousPostfix,
  69. StringRef CurrentPrefix, bool InPPDirective,
  70. unsigned Newlines, unsigned IndentLevel,
  71. int Spaces);
  72. /// \brief Returns all the \c Replacements created during formatting.
  73. const tooling::Replacements &generateReplacements();
  74. private:
  75. /// \brief Represents a change before a token, a break inside a token,
  76. /// or the layout of an unchanged token (or whitespace within).
  77. struct Change {
  78. /// \brief Functor to sort changes in original source order.
  79. class IsBeforeInFile {
  80. public:
  81. IsBeforeInFile(const SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
  82. bool operator()(const Change &C1, const Change &C2) const;
  83. private:
  84. const SourceManager &SourceMgr;
  85. };
  86. Change() {}
  87. /// \brief Creates a \c Change.
  88. ///
  89. /// The generated \c Change will replace the characters at
  90. /// \p OriginalWhitespaceRange with a concatenation of
  91. /// \p PreviousLinePostfix, \p NewlinesBefore line breaks, \p Spaces spaces
  92. /// and \p CurrentLinePrefix.
  93. ///
  94. /// \p StartOfTokenColumn and \p InPPDirective will be used to lay out
  95. /// trailing comments and escaped newlines.
  96. Change(bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
  97. unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
  98. unsigned NewlinesBefore, StringRef PreviousLinePostfix,
  99. StringRef CurrentLinePrefix, tok::TokenKind Kind,
  100. bool ContinuesPPDirective);
  101. bool CreateReplacement;
  102. // Changes might be in the middle of a token, so we cannot just keep the
  103. // FormatToken around to query its information.
  104. SourceRange OriginalWhitespaceRange;
  105. unsigned StartOfTokenColumn;
  106. unsigned NewlinesBefore;
  107. std::string PreviousLinePostfix;
  108. std::string CurrentLinePrefix;
  109. // The kind of the token whose whitespace this change replaces, or in which
  110. // this change inserts whitespace.
  111. // FIXME: Currently this is not set correctly for breaks inside comments, as
  112. // the \c BreakableToken is still doing its own alignment.
  113. tok::TokenKind Kind;
  114. bool ContinuesPPDirective;
  115. // The number of nested blocks the token is in. This is used to add tabs
  116. // only for the indentation, and not for alignment, when
  117. // UseTab = US_ForIndentation.
  118. unsigned IndentLevel;
  119. // The number of spaces in front of the token or broken part of the token.
  120. // This will be adapted when aligning tokens.
  121. // Can be negative to retain information about the initial relative offset
  122. // of the lines in a block comment. This is used when aligning trailing
  123. // comments. Uncompensated negative offset is truncated to 0.
  124. int Spaces;
  125. // \c IsTrailingComment, \c TokenLength, \c PreviousEndOfTokenColumn and
  126. // \c EscapedNewlineColumn will be calculated in
  127. // \c calculateLineBreakInformation.
  128. bool IsTrailingComment;
  129. unsigned TokenLength;
  130. unsigned PreviousEndOfTokenColumn;
  131. unsigned EscapedNewlineColumn;
  132. // These fields are used to retain correct relative line indentation in a
  133. // block comment when aligning trailing comments.
  134. //
  135. // If this Change represents a continuation of a block comment,
  136. // \c StartOfBlockComment is pointer to the first Change in the block
  137. // comment. \c IndentationOffset is a relative column offset to this
  138. // change, so that the correct column can be reconstructed at the end of
  139. // the alignment process.
  140. const Change *StartOfBlockComment;
  141. int IndentationOffset;
  142. };
  143. /// \brief Calculate \c IsTrailingComment, \c TokenLength for the last tokens
  144. /// or token parts in a line and \c PreviousEndOfTokenColumn and
  145. /// \c EscapedNewlineColumn for the first tokens or token parts in a line.
  146. void calculateLineBreakInformation();
  147. /// \brief Align consecutive assignments over all \c Changes.
  148. void alignConsecutiveAssignments();
  149. /// \brief Align consecutive assignments from change \p Start to change \p End
  150. /// at
  151. /// the specified \p Column.
  152. void alignConsecutiveAssignments(unsigned Start, unsigned End,
  153. unsigned Column);
  154. /// \brief Align trailing comments over all \c Changes.
  155. void alignTrailingComments();
  156. /// \brief Align trailing comments from change \p Start to change \p End at
  157. /// the specified \p Column.
  158. void alignTrailingComments(unsigned Start, unsigned End, unsigned Column);
  159. /// \brief Align escaped newlines over all \c Changes.
  160. void alignEscapedNewlines();
  161. /// \brief Align escaped newlines from change \p Start to change \p End at
  162. /// the specified \p Column.
  163. void alignEscapedNewlines(unsigned Start, unsigned End, unsigned Column);
  164. /// \brief Fill \c Replaces with the replacements for all effective changes.
  165. void generateChanges();
  166. /// \brief Stores \p Text as the replacement for the whitespace in \p Range.
  167. void storeReplacement(const SourceRange &Range, StringRef Text);
  168. void appendNewlineText(std::string &Text, unsigned Newlines);
  169. void appendNewlineText(std::string &Text, unsigned Newlines,
  170. unsigned PreviousEndOfTokenColumn,
  171. unsigned EscapedNewlineColumn);
  172. void appendIndentText(std::string &Text, unsigned IndentLevel,
  173. unsigned Spaces, unsigned WhitespaceStartColumn);
  174. SmallVector<Change, 16> Changes;
  175. SourceManager &SourceMgr;
  176. tooling::Replacements Replaces;
  177. const FormatStyle &Style;
  178. bool UseCRLF;
  179. };
  180. } // namespace format
  181. } // namespace clang
  182. #endif