You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
10 KiB
246 lines
10 KiB
//===--- 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_LIB_FORMAT_BREAKABLETOKEN_H
|
|
#define LLVM_CLANG_LIB_FORMAT_BREAKABLETOKEN_H
|
|
|
|
#include "Encoding.h"
|
|
#include "TokenAnnotator.h"
|
|
#include "WhitespaceManager.h"
|
|
#include <utility>
|
|
|
|
namespace clang {
|
|
namespace format {
|
|
|
|
struct FormatStyle;
|
|
|
|
/// \brief Base class for strategies on how to break tokens.
|
|
///
|
|
/// FIXME: The interface seems set in stone, so we might want to just pull the
|
|
/// strategy into the class, instead of controlling it from the outside.
|
|
class BreakableToken {
|
|
public:
|
|
/// \brief Contains starting character index and length of split.
|
|
typedef std::pair<StringRef::size_type, unsigned> Split;
|
|
|
|
virtual ~BreakableToken() {}
|
|
|
|
/// \brief Returns the number of lines in this token in the original code.
|
|
virtual unsigned getLineCount() const = 0;
|
|
|
|
/// \brief Returns the number of columns required to format the piece of line
|
|
/// at \p LineIndex, from byte offset \p Offset with length \p Length.
|
|
///
|
|
/// Note that previous breaks are not taken into account. \p Offset is always
|
|
/// specified from the start of the (original) line.
|
|
/// \p Length can be set to StringRef::npos, which means "to the end of line".
|
|
virtual unsigned
|
|
getLineLengthAfterSplit(unsigned LineIndex, unsigned Offset,
|
|
StringRef::size_type Length) const = 0;
|
|
|
|
/// \brief Returns a range (offset, length) at which to break the line at
|
|
/// \p LineIndex, if previously broken at \p TailOffset. If possible, do not
|
|
/// violate \p ColumnLimit.
|
|
virtual Split getSplit(unsigned LineIndex, unsigned TailOffset,
|
|
unsigned ColumnLimit) const = 0;
|
|
|
|
/// \brief Emits the previously retrieved \p Split via \p Whitespaces.
|
|
virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
|
|
WhitespaceManager &Whitespaces) = 0;
|
|
|
|
/// \brief Replaces the whitespace range described by \p Split with a single
|
|
/// space.
|
|
virtual void replaceWhitespace(unsigned LineIndex, unsigned TailOffset,
|
|
Split Split,
|
|
WhitespaceManager &Whitespaces) = 0;
|
|
|
|
/// \brief Replaces the whitespace between \p LineIndex-1 and \p LineIndex.
|
|
virtual void replaceWhitespaceBefore(unsigned LineIndex,
|
|
WhitespaceManager &Whitespaces) {}
|
|
|
|
protected:
|
|
BreakableToken(const FormatToken &Tok, unsigned IndentLevel,
|
|
bool InPPDirective, encoding::Encoding Encoding,
|
|
const FormatStyle &Style)
|
|
: Tok(Tok), IndentLevel(IndentLevel), InPPDirective(InPPDirective),
|
|
Encoding(Encoding), Style(Style) {}
|
|
|
|
const FormatToken &Tok;
|
|
const unsigned IndentLevel;
|
|
const bool InPPDirective;
|
|
const encoding::Encoding Encoding;
|
|
const FormatStyle &Style;
|
|
};
|
|
|
|
/// \brief Base class for single line tokens that can be broken.
|
|
///
|
|
/// \c getSplit() needs to be implemented by child classes.
|
|
class BreakableSingleLineToken : public BreakableToken {
|
|
public:
|
|
unsigned getLineCount() const override;
|
|
unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
|
|
StringRef::size_type Length) const override;
|
|
|
|
protected:
|
|
BreakableSingleLineToken(const FormatToken &Tok, unsigned IndentLevel,
|
|
unsigned StartColumn, StringRef Prefix,
|
|
StringRef Postfix, bool InPPDirective,
|
|
encoding::Encoding Encoding,
|
|
const FormatStyle &Style);
|
|
|
|
// The column in which the token starts.
|
|
unsigned StartColumn;
|
|
// The prefix a line needs after a break in the token.
|
|
StringRef Prefix;
|
|
// The postfix a line needs before introducing a break.
|
|
StringRef Postfix;
|
|
// The token text excluding the prefix and postfix.
|
|
StringRef Line;
|
|
};
|
|
|
|
class BreakableStringLiteral : public BreakableSingleLineToken {
|
|
public:
|
|
/// \brief Creates a breakable token for a single line string literal.
|
|
///
|
|
/// \p StartColumn specifies the column in which the token will start
|
|
/// after formatting.
|
|
BreakableStringLiteral(const FormatToken &Tok, unsigned IndentLevel,
|
|
unsigned StartColumn, StringRef Prefix,
|
|
StringRef Postfix, bool InPPDirective,
|
|
encoding::Encoding Encoding, const FormatStyle &Style);
|
|
|
|
Split getSplit(unsigned LineIndex, unsigned TailOffset,
|
|
unsigned ColumnLimit) const override;
|
|
void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
|
|
WhitespaceManager &Whitespaces) override;
|
|
void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
|
|
WhitespaceManager &Whitespaces) override {}
|
|
};
|
|
|
|
class BreakableLineComment : public BreakableSingleLineToken {
|
|
public:
|
|
/// \brief Creates a breakable token for a line comment.
|
|
///
|
|
/// \p StartColumn specifies the column in which the comment will start
|
|
/// after formatting.
|
|
BreakableLineComment(const FormatToken &Token, unsigned IndentLevel,
|
|
unsigned StartColumn, bool InPPDirective,
|
|
encoding::Encoding Encoding, const FormatStyle &Style);
|
|
|
|
Split getSplit(unsigned LineIndex, unsigned TailOffset,
|
|
unsigned ColumnLimit) const override;
|
|
void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
|
|
WhitespaceManager &Whitespaces) override;
|
|
void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
|
|
WhitespaceManager &Whitespaces) override;
|
|
void replaceWhitespaceBefore(unsigned LineIndex,
|
|
WhitespaceManager &Whitespaces) override;
|
|
|
|
private:
|
|
// The prefix without an additional space if one was added.
|
|
StringRef OriginalPrefix;
|
|
};
|
|
|
|
class BreakableBlockComment : public BreakableToken {
|
|
public:
|
|
/// \brief Creates a breakable token for a block comment.
|
|
///
|
|
/// \p StartColumn specifies the column in which the comment will start
|
|
/// after formatting, while \p OriginalStartColumn specifies in which
|
|
/// column the comment started before formatting.
|
|
/// If the comment starts a line after formatting, set \p FirstInLine to true.
|
|
BreakableBlockComment(const FormatToken &Token, unsigned IndentLevel,
|
|
unsigned StartColumn, unsigned OriginaStartColumn,
|
|
bool FirstInLine, bool InPPDirective,
|
|
encoding::Encoding Encoding, const FormatStyle &Style);
|
|
|
|
unsigned getLineCount() const override;
|
|
unsigned getLineLengthAfterSplit(unsigned LineIndex, unsigned TailOffset,
|
|
StringRef::size_type Length) const override;
|
|
Split getSplit(unsigned LineIndex, unsigned TailOffset,
|
|
unsigned ColumnLimit) const override;
|
|
void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split,
|
|
WhitespaceManager &Whitespaces) override;
|
|
void replaceWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split,
|
|
WhitespaceManager &Whitespaces) override;
|
|
void replaceWhitespaceBefore(unsigned LineIndex,
|
|
WhitespaceManager &Whitespaces) override;
|
|
|
|
private:
|
|
// Rearranges the whitespace between Lines[LineIndex-1] and Lines[LineIndex],
|
|
// so that all whitespace between the lines is accounted to Lines[LineIndex]
|
|
// as leading whitespace:
|
|
// - Lines[LineIndex] points to the text after that whitespace
|
|
// - Lines[LineIndex-1] shrinks by its trailing whitespace
|
|
// - LeadingWhitespace[LineIndex] is updated with the complete whitespace
|
|
// between the end of the text of Lines[LineIndex-1] and Lines[LineIndex]
|
|
//
|
|
// Sets StartOfLineColumn to the intended column in which the text at
|
|
// Lines[LineIndex] starts (note that the decoration, if present, is not
|
|
// considered part of the text).
|
|
void adjustWhitespace(unsigned LineIndex, int IndentDelta);
|
|
|
|
// Returns the column at which the text in line LineIndex starts, when broken
|
|
// at TailOffset. Note that the decoration (if present) is not considered part
|
|
// of the text.
|
|
unsigned getContentStartColumn(unsigned LineIndex, unsigned TailOffset) const;
|
|
|
|
// Contains the text of the lines of the block comment, excluding the leading
|
|
// /* in the first line and trailing */ in the last line, and excluding all
|
|
// trailing whitespace between the lines. Note that the decoration (if
|
|
// present) is also not considered part of the text.
|
|
SmallVector<StringRef, 16> Lines;
|
|
|
|
// LeadingWhitespace[i] is the number of characters regarded as whitespace in
|
|
// front of Lines[i]. Note that this can include "* " sequences, which we
|
|
// regard as whitespace when all lines have a "*" prefix.
|
|
SmallVector<unsigned, 16> LeadingWhitespace;
|
|
|
|
// StartOfLineColumn[i] is the target column at which Line[i] should be.
|
|
// Note that this excludes a leading "* " or "*" in case all lines have
|
|
// a "*" prefix.
|
|
// The first line's target column is always positive. The remaining lines'
|
|
// target columns are relative to the first line to allow correct indentation
|
|
// of comments in \c WhitespaceManager. Thus they can be negative as well (in
|
|
// case the first line needs to be unindented more than there's actual
|
|
// whitespace in another line).
|
|
SmallVector<int, 16> StartOfLineColumn;
|
|
|
|
// The column at which the text of a broken line should start.
|
|
// Note that an optional decoration would go before that column.
|
|
// IndentAtLineBreak is a uniform position for all lines in a block comment,
|
|
// regardless of their relative position.
|
|
// FIXME: Revisit the decision to do this; the main reason was to support
|
|
// patterns like
|
|
// /**************//**
|
|
// * Comment
|
|
// We could also support such patterns by special casing the first line
|
|
// instead.
|
|
unsigned IndentAtLineBreak;
|
|
|
|
// This is to distinguish between the case when the last line was empty and
|
|
// the case when it started with a decoration ("*" or "* ").
|
|
bool LastLineNeedsDecoration;
|
|
|
|
// Either "* " if all lines begin with a "*", or empty.
|
|
StringRef Decoration;
|
|
};
|
|
|
|
} // namespace format
|
|
} // namespace clang
|
|
|
|
#endif
|