summaryrefslogtreecommitdiffstats
path: root/lib/Format/BreakableToken.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Format/BreakableToken.h')
-rw-r--r--lib/Format/BreakableToken.h240
1 files changed, 240 insertions, 0 deletions
diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
new file mode 100644
index 0000000..c130318
--- /dev/null
+++ b/lib/Format/BreakableToken.h
@@ -0,0 +1,240 @@
+//===--- BreakableToken.h - Format C++ code -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Declares BreakableToken, BreakableStringLiteral, and
+/// BreakableBlockComment classes, that contain token type-specific logic to
+/// break long lines in tokens.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
+#define LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
+
+#include "TokenAnnotator.h"
+#include "WhitespaceManager.h"
+#include <utility>
+
+namespace clang {
+namespace format {
+
+class BreakableToken {
+public:
+ BreakableToken(const SourceManager &SourceMgr, const FormatToken &Tok,
+ unsigned StartColumn)
+ : Tok(Tok), StartColumn(StartColumn),
+ TokenText(SourceMgr.getCharacterData(Tok.getStartOfNonWhitespace()),
+ Tok.TokenLength) {}
+ virtual ~BreakableToken() {}
+ virtual unsigned getLineCount() const = 0;
+ virtual unsigned getLineSize(unsigned Index) const = 0;
+ virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
+ unsigned TailOffset) const = 0;
+
+ // Contains starting character index and length of split.
+ typedef std::pair<StringRef::size_type, unsigned> Split;
+ virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const = 0;
+ virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ bool InPPDirective,
+ WhitespaceManager &Whitespaces) = 0;
+ virtual void trimLine(unsigned LineIndex, unsigned TailOffset,
+ unsigned InPPDirective,
+ WhitespaceManager &Whitespaces) {}
+protected:
+ const FormatToken &Tok;
+ unsigned StartColumn;
+ StringRef TokenText;
+};
+
+class BreakableStringLiteral : public BreakableToken {
+public:
+ BreakableStringLiteral(const SourceManager &SourceMgr, const FormatToken &Tok,
+ unsigned StartColumn)
+ : BreakableToken(SourceMgr, Tok, StartColumn) {
+ assert(TokenText.startswith("\"") && TokenText.endswith("\""));
+ }
+
+ virtual unsigned getLineCount() const { return 1; }
+
+ virtual unsigned getLineSize(unsigned Index) const {
+ return Tok.TokenLength - 2; // Should be in sync with getLine
+ }
+
+ virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
+ unsigned TailOffset) const {
+ return getDecorationLength() + getLine().size() - TailOffset;
+ }
+
+ virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const {
+ StringRef Text = getLine().substr(TailOffset);
+ if (ColumnLimit <= getDecorationLength())
+ return Split(StringRef::npos, 0);
+ unsigned MaxSplit = ColumnLimit - getDecorationLength();
+ assert(MaxSplit < Text.size());
+ StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit);
+ if (SpaceOffset != StringRef::npos && SpaceOffset != 0)
+ return Split(SpaceOffset + 1, 0);
+ StringRef::size_type SlashOffset = Text.rfind('/', MaxSplit);
+ if (SlashOffset != StringRef::npos && SlashOffset != 0)
+ return Split(SlashOffset + 1, 0);
+ StringRef::size_type SplitPoint = getStartOfCharacter(Text, MaxSplit);
+ if (SplitPoint != StringRef::npos && SplitPoint > 1)
+ // Do not split at 0.
+ return Split(SplitPoint, 0);
+ return Split(StringRef::npos, 0);
+ }
+
+ virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ bool InPPDirective, WhitespaceManager &Whitespaces) {
+ unsigned WhitespaceStartColumn = StartColumn + Split.first + 2;
+ Whitespaces.breakToken(Tok, 1 + TailOffset + Split.first, Split.second,
+ "\"", "\"", InPPDirective, StartColumn,
+ WhitespaceStartColumn);
+ }
+
+private:
+ StringRef getLine() const {
+ // Get string without quotes.
+ // FIXME: Handle string prefixes.
+ return TokenText.substr(1, TokenText.size() - 2);
+ }
+
+ unsigned getDecorationLength() const { return StartColumn + 2; }
+
+ static StringRef::size_type getStartOfCharacter(StringRef Text,
+ StringRef::size_type Offset) {
+ StringRef::size_type NextEscape = Text.find('\\');
+ while (NextEscape != StringRef::npos && NextEscape < Offset) {
+ StringRef::size_type SequenceLength =
+ getEscapeSequenceLength(Text.substr(NextEscape));
+ if (Offset < NextEscape + SequenceLength)
+ return NextEscape;
+ NextEscape = Text.find('\\', NextEscape + SequenceLength);
+ }
+ return Offset;
+ }
+
+ static unsigned getEscapeSequenceLength(StringRef Text) {
+ assert(Text[0] == '\\');
+ if (Text.size() < 2)
+ return 1;
+
+ switch (Text[1]) {
+ case 'u':
+ return 6;
+ case 'U':
+ return 10;
+ case 'x':
+ return getHexLength(Text);
+ default:
+ if (Text[1] >= '0' && Text[1] <= '7')
+ return getOctalLength(Text);
+ return 2;
+ }
+ }
+
+ static unsigned getHexLength(StringRef Text) {
+ unsigned I = 2; // Point after '\x'.
+ while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') ||
+ (Text[I] >= 'a' && Text[I] <= 'f') ||
+ (Text[I] >= 'A' && Text[I] <= 'F'))) {
+ ++I;
+ }
+ return I;
+ }
+
+ static unsigned getOctalLength(StringRef Text) {
+ unsigned I = 1;
+ while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) {
+ ++I;
+ }
+ return I;
+ }
+
+};
+
+class BreakableComment : public BreakableToken {
+public:
+ virtual unsigned getLineSize(unsigned Index) const {
+ return getLine(Index).size();
+ }
+
+ virtual unsigned getLineCount() const { return Lines.size(); }
+
+ virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
+ unsigned TailOffset) const {
+ return getContentStartColumn(LineIndex, TailOffset) +
+ getLine(LineIndex).size() - TailOffset;
+ }
+
+ virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
+ unsigned ColumnLimit) const;
+ virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
+ bool InPPDirective, WhitespaceManager &Whitespaces);
+
+protected:
+ BreakableComment(const SourceManager &SourceMgr, const FormatToken &Tok,
+ unsigned StartColumn)
+ : BreakableToken(SourceMgr, Tok, StartColumn) {}
+
+ // Get comment lines without /* */, common prefix and trailing whitespace.
+ // Last line is not trimmed, as it is terminated by */, so its trailing
+ // whitespace is not really trailing.
+ StringRef getLine(unsigned Index) const {
+ return Index < Lines.size() - 1 ? Lines[Index].rtrim() : Lines[Index];
+ }
+
+ unsigned getContentStartColumn(unsigned LineIndex,
+ unsigned TailOffset) const {
+ return (TailOffset == 0 && LineIndex == 0)
+ ? StartColumn
+ : IndentAtLineBreak + Decoration.size();
+ }
+
+ unsigned IndentAtLineBreak;
+ StringRef Decoration;
+ SmallVector<StringRef, 16> Lines;
+};
+
+class BreakableBlockComment : public BreakableComment {
+public:
+ BreakableBlockComment(const SourceManager &SourceMgr,
+ const AnnotatedToken &Token, unsigned StartColumn);
+
+ void alignLines(WhitespaceManager &Whitespaces);
+
+ virtual unsigned getLineLengthAfterSplit(unsigned LineIndex,
+ unsigned TailOffset) const {
+ return BreakableComment::getLineLengthAfterSplit(LineIndex, TailOffset) +
+ (LineIndex + 1 < Lines.size() ? 0 : 2);
+ }
+
+ virtual void trimLine(unsigned LineIndex, unsigned TailOffset,
+ unsigned InPPDirective, WhitespaceManager &Whitespaces);
+
+private:
+ unsigned OriginalStartColumn;
+ unsigned CommonPrefixLength;
+};
+
+class BreakableLineComment : public BreakableComment {
+public:
+ BreakableLineComment(const SourceManager &SourceMgr,
+ const AnnotatedToken &Token, unsigned StartColumn);
+
+private:
+ static StringRef getLineCommentPrefix(StringRef Comment);
+};
+
+} // namespace format
+} // namespace clang
+
+#endif // LLVM_CLANG_FORMAT_BREAKABLETOKEN_H
OpenPOWER on IntegriCloud