//===--- Format.cpp - 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 This file implements functions declared in Format.h. This will be
/// split into separate files as we go.
///
/// This is EXPERIMENTAL code under heavy development. It is not in a state yet,
/// where it can be used to format real code.
///
//===----------------------------------------------------------------------===//
#include "clang/Format/Format.h"
#include "UnwrappedLineParser.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Lex/Lexer.h"
#include <string>
namespace clang {
namespace format {
// FIXME: Move somewhere sane.
struct TokenAnnotation {
enum TokenType {
TT_Unknown,
TT_TemplateOpener,
TT_TemplateCloser,
TT_BinaryOperator,
TT_UnaryOperator,
TT_TrailingUnaryOperator,
TT_OverloadedOperator,
TT_PointerOrReference,
TT_ConditionalExpr,
TT_CtorInitializerColon,
TT_LineComment,
TT_BlockComment,
TT_DirectorySeparator,
TT_ObjCMethodSpecifier
};
TokenType Type;
bool SpaceRequiredBefore;
bool CanBreakBefore;
bool MustBreakBefore;
};
using llvm::MutableArrayRef;
FormatStyle getLLVMStyle() {
FormatStyle LLVMStyle;
LLVMStyle.ColumnLimit = 80;
LLVMStyle.MaxEmptyLinesToKeep = 1;
LLVMStyle.PointerAndReferenceBindToType = false;
LLVMStyle.AccessModifierOffset = -2;
LLVMStyle.SplitTemplateClosingGreater = true;
LLVMStyle.IndentCaseLabels = false;
return LLVMStyle;
}
FormatStyle getGoogleStyle() {
FormatStyle GoogleStyle;
GoogleStyle.ColumnLimit = 80;
GoogleStyle.MaxEmptyLinesToKeep = 1;
GoogleStyle.PointerAndReferenceBindToType = true;
GoogleStyle.AccessModifierOffset = -1;
GoogleStyle.SplitTemplateClosingGreater = false;
GoogleStyle.IndentCaseLabels = true;
return GoogleStyle;
}
struct OptimizationParameters {
unsigned PenaltyIndentLevel;
};
class UnwrappedLineFormatter {
public:
UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
const UnwrappedLine &Line,
const std::vector<TokenAnnotation> &Annotations,
tooling::Replacements &Replaces, bool StructuralError)
: Style(Style), SourceMgr(SourceMgr), Line(Line),
Annotations(Annotations), Replaces(Replaces),
StructuralError(StructuralError) {
Parameters.PenaltyIndentLevel = 5;
}
void format() {
// Format first token and initialize indent.
unsigned Indent = formatFirstToken();
// Initialize state dependent on indent.
IndentState State;
State.Column = Indent;
State.ConsumedTokens = 0;
State.Indent.push_back(Indent + 4);
State.LastSpace.push_back(Indent);
State.FirstLessLess.push_back(0);
State.ForLoopVariablePos = 0;
State.LineContainsContinuedForLoopSection = false;
// The first token has already been indented and thus consumed.
moveStateToNextToken(State);
// Check whether the UnwrappedLine can be put onto a single line. If so,
// this is bound to be the optimal solution (by definition) and we don't
// need to analyze the entire solution space.
unsigned Columns = State.Column;
bool FitsOnALine = true;
for (unsigned i = 1, n = Line.Tokens.size(); i != n; ++i) {
Columns += (Annotations[i].SpaceRequiredBefore ? 1 : 0) +
Line.Tokens[i].Tok.getLength();
// A special case for the colon of a constructor initializer as this only
// needs to be put on a new line if the line needs to be split.
if (Columns > Style.ColumnLimit ||
(Annotations[i].MustBreakBefore &&
Annotations[i].Type != TokenAnnotation::TT_CtorInitializerColon)) {
FitsOnALine = false;
break;
}
}
// Start iterating at 1 as we have correctly formatted of Token #0 above.
for (unsigned i = 1, n = Line.Tokens.size(); i != n; ++i) {
if (FitsOnALine) {
addTokenToState(false, false, State);
} else {
unsigned NoBreak = calcPenalty(State, false, UINT_MAX);
unsigned Break = calcPenalty(State, true, NoBreak);
addTokenToState(Break < NoBreak, false, State);
}
}
}
private:
/// \brief The current state when indenting a unwrapped line.
///
/// As the indenting tries different combinations this is copied by value.
struct IndentState {
/// \brief The number of used columns in the current line.
unsigned Column;
/// \brief The number of tokens already consumed.
unsigned ConsumedTokens;
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
std::vector<unsigned&g