Pulling formatFirstToken one level up.

This prepares the code for single line optimizations and changes the
dependencies between single-line-formats to the indent of the first
token.

Conceptually, the first token is "between" the lines anyway, as the
whitespace for the first token includes the previous end-of-line, which
needs to be escaped when inside a preprocessor directive.

llvm-svn: 172083
This commit is contained in:
Manuel Klimek 2013-01-10 18:45:26 +00:00
parent f0615c71fa
commit 0b689fd68d
1 changed files with 91 additions and 85 deletions

View File

@ -123,17 +123,52 @@ struct OptimizationParameters {
unsigned PenaltyExcessCharacter;
};
/// \brief Replaces the whitespace in front of \p Tok. Only call once for
/// each \c FormatToken.
static void replaceWhitespace(const AnnotatedToken &Tok, unsigned NewLines,
unsigned Spaces, const FormatStyle &Style,
SourceManager &SourceMgr,
tooling::Replacements &Replaces) {
Replaces.insert(tooling::Replacement(
SourceMgr, Tok.FormatTok.WhiteSpaceStart, Tok.FormatTok.WhiteSpaceLength,
std::string(NewLines, '\n') + std::string(Spaces, ' ')));
}
/// \brief Like \c replaceWhitespace, but additionally adds right-aligned
/// backslashes to escape newlines inside a preprocessor directive.
///
/// This function and \c replaceWhitespace have the same behavior if
/// \c Newlines == 0.
static void replacePPWhitespace(
const AnnotatedToken &Tok, unsigned NewLines, unsigned Spaces,
unsigned WhitespaceStartColumn, const FormatStyle &Style,
SourceManager &SourceMgr, tooling::Replacements &Replaces) {
std::string NewLineText;
if (NewLines > 0) {
unsigned Offset = std::min<int>(Style.ColumnLimit - 1,
WhitespaceStartColumn);
for (unsigned i = 0; i < NewLines; ++i) {
NewLineText += std::string(Style.ColumnLimit - Offset - 1, ' ');
NewLineText += "\\\n";
Offset = 0;
}
}
Replaces.insert(tooling::Replacement(SourceMgr, Tok.FormatTok.WhiteSpaceStart,
Tok.FormatTok.WhiteSpaceLength,
NewLineText + std::string(Spaces, ' ')));
}
class UnwrappedLineFormatter {
public:
UnwrappedLineFormatter(
const FormatStyle &Style, SourceManager &SourceMgr,
const UnwrappedLine &Line, unsigned PreviousEndOfLineColumn,
const UnwrappedLine &Line, unsigned FirstIndent,
LineType CurrentLineType, const AnnotatedToken &RootToken,
tooling::Replacements &Replaces, bool StructuralError)
: Style(Style), SourceMgr(SourceMgr), Line(Line),
PreviousEndOfLineColumn(PreviousEndOfLineColumn),
FirstIndent(FirstIndent),
CurrentLineType(CurrentLineType), RootToken(RootToken),
Replaces(Replaces), StructuralError(StructuralError) {
Replaces(Replaces) {
Parameters.PenaltyIndentLevel = 15;
Parameters.PenaltyLevelDecrease = 30;
Parameters.PenaltyExcessCharacter = 1000000;
@ -144,15 +179,12 @@ public:
/// \returns The column after the last token in the last line of the
/// \c UnwrappedLine.
unsigned format() {
// Format first token and initialize indent.
unsigned Indent = formatFirstToken();
// Initialize state dependent on indent.
IndentState State;
State.Column = Indent;
State.Column = FirstIndent;
State.NextToken = &RootToken;
State.Indent.push_back(Indent + 4);
State.LastSpace.push_back(Indent);
State.Indent.push_back(FirstIndent + 4);
State.LastSpace.push_back(FirstIndent);
State.FirstLessLess.push_back(0);
State.BreakBeforeClosingBrace.push_back(false);
State.ForLoopVariablePos = 0;
@ -325,10 +357,12 @@ private:
if (!DryRun) {
if (!Line.InPPDirective)
replaceWhitespace(Current.FormatTok, 1, State.Column);
replaceWhitespace(Current.FormatTok, 1, State.Column, Style,
SourceMgr, Replaces);
else
replacePPWhitespace(Current.FormatTok, 1, State.Column,
WhitespaceStartColumn);
WhitespaceStartColumn, Style, SourceMgr,
Replaces);
}
State.LastSpace[ParenLevel] = State.Column;
@ -345,7 +379,7 @@ private:
Spaces = Style.SpacesBeforeTrailingComments;
if (!DryRun)
replaceWhitespace(Current, 0, Spaces);
replaceWhitespace(Current, 0, Spaces, Style, SourceMgr, Replaces);
// FIXME: Do we need to do this for assignments nested in other
// expressions?
@ -528,82 +562,13 @@ private:
return Result == UINT_MAX ? UINT_MAX : Result + CurrentPenalty;
}
/// \brief Replaces the whitespace in front of \p Tok. Only call once for
/// each \c FormatToken.
void replaceWhitespace(const AnnotatedToken &Tok, unsigned NewLines,
unsigned Spaces) {
Replaces.insert(tooling::Replacement(
SourceMgr, Tok.FormatTok.WhiteSpaceStart,
Tok.FormatTok.WhiteSpaceLength,
std::string(NewLines, '\n') + std::string(Spaces, ' ')));
}
/// \brief Like \c replaceWhitespace, but additionally adds right-aligned
/// backslashes to escape newlines inside a preprocessor directive.
///
/// This function and \c replaceWhitespace have the same behavior if
/// \c Newlines == 0.
void replacePPWhitespace(const AnnotatedToken &Tok, unsigned NewLines,
unsigned Spaces, unsigned WhitespaceStartColumn) {
std::string NewLineText;
if (NewLines > 0) {
unsigned Offset = std::min<int>(Style.ColumnLimit - 1,
WhitespaceStartColumn);
for (unsigned i = 0; i < NewLines; ++i) {
NewLineText += std::string(Style.ColumnLimit - Offset - 1, ' ');
NewLineText += "\\\n";
Offset = 0;
}
}
Replaces.insert(
tooling::Replacement(SourceMgr, Tok.FormatTok.WhiteSpaceStart,
Tok.FormatTok.WhiteSpaceLength,
NewLineText + std::string(Spaces, ' ')));
}
/// \brief Add a new line and the required indent before the first Token
/// of the \c UnwrappedLine if there was no structural parsing error.
/// Returns the indent level of the \c UnwrappedLine.
unsigned formatFirstToken() {
const FormatToken &Tok = RootToken.FormatTok;
if (!Tok.WhiteSpaceStart.isValid() || StructuralError)
return SourceMgr.getSpellingColumnNumber(Tok.Tok.getLocation()) - 1;
unsigned Newlines = std::min(Tok.NewlinesBefore,
Style.MaxEmptyLinesToKeep + 1);
if (Newlines == 0 && !Tok.IsFirst)
Newlines = 1;
unsigned Indent = Line.Level * 2;
bool IsAccessModifier = false;
if (RootToken.is(tok::kw_public) || RootToken.is(tok::kw_protected) ||
RootToken.is(tok::kw_private))
IsAccessModifier = true;
else if (RootToken.is(tok::at) && !RootToken.Children.empty() &&
(RootToken.Children[0].isObjCAtKeyword(tok::objc_public) ||
RootToken.Children[0].isObjCAtKeyword(tok::objc_protected) ||
RootToken.Children[0].isObjCAtKeyword(tok::objc_package) ||
RootToken.Children[0].isObjCAtKeyword(tok::objc_private)))
IsAccessModifier = true;
if (IsAccessModifier &&
static_cast<int>(Indent) + Style.AccessModifierOffset >= 0)
Indent += Style.AccessModifierOffset;
if (!Line.InPPDirective || Tok.HasUnescapedNewline)
replaceWhitespace(Tok, Newlines, Indent);
else
replacePPWhitespace(Tok, Newlines, Indent, PreviousEndOfLineColumn);
return Indent;
}
FormatStyle Style;
SourceManager &SourceMgr;
const UnwrappedLine &Line;
const unsigned PreviousEndOfLineColumn;
const unsigned FirstIndent;
const LineType CurrentLineType;
const AnnotatedToken &RootToken;
tooling::Replacements &Replaces;
bool StructuralError;
// A map from an indent state to a pair (Result, Used-StopAt).
typedef std::map<IndentState, std::pair<unsigned, unsigned> > StateMap;
@ -1245,8 +1210,7 @@ public:
Lexer &Lex, SourceManager &SourceMgr,
const std::vector<CharSourceRange> &Ranges)
: Diag(Diag), Style(Style), Lex(Lex), SourceMgr(SourceMgr),
Ranges(Ranges), StructuralError(false) {
}
Ranges(Ranges) {}
virtual ~Formatter() {
}
@ -1289,8 +1253,11 @@ private:
TokenAnnotator Annotator(TheLine, Style, SourceMgr, Lex);
if (!Annotator.annotate())
break;
unsigned Indent = formatFirstToken(Annotator.getRootToken(),
TheLine.Level, TheLine.InPPDirective,
PreviousEndOfLineColumn);
UnwrappedLineFormatter Formatter(
Style, SourceMgr, TheLine, PreviousEndOfLineColumn,
Style, SourceMgr, TheLine, Indent,
Annotator.getLineType(), Annotator.getRootToken(), Replaces,
StructuralError);
return Formatter.format();
@ -1304,6 +1271,45 @@ private:
1;
}
/// \brief Add a new line and the required indent before the first Token
/// of the \c UnwrappedLine if there was no structural parsing error.
/// Returns the indent level of the \c UnwrappedLine.
unsigned formatFirstToken(const AnnotatedToken &RootToken, unsigned Level,
bool InPPDirective,
unsigned PreviousEndOfLineColumn) {
const FormatToken& Tok = RootToken.FormatTok;
if (!Tok.WhiteSpaceStart.isValid() || StructuralError)
return SourceMgr.getSpellingColumnNumber(Tok.Tok.getLocation()) - 1;
unsigned Newlines = std::min(Tok.NewlinesBefore,
Style.MaxEmptyLinesToKeep + 1);
if (Newlines == 0 && !Tok.IsFirst)
Newlines = 1;
unsigned Indent = Level * 2;
bool IsAccessModifier = false;
if (RootToken.is(tok::kw_public) || RootToken.is(tok::kw_protected) ||
RootToken.is(tok::kw_private))
IsAccessModifier = true;
else if (RootToken.is(tok::at) && !RootToken.Children.empty() &&
(RootToken.Children[0].isObjCAtKeyword(tok::objc_public) ||
RootToken.Children[0].isObjCAtKeyword(tok::objc_protected) ||
RootToken.Children[0].isObjCAtKeyword(tok::objc_package) ||
RootToken.Children[0].isObjCAtKeyword(tok::objc_private)))
IsAccessModifier = true;
if (IsAccessModifier &&
static_cast<int>(Indent) + Style.AccessModifierOffset >= 0)
Indent += Style.AccessModifierOffset;
if (!InPPDirective || Tok.HasUnescapedNewline) {
replaceWhitespace(Tok, Newlines, Indent, Style, SourceMgr, Replaces);
} else {
replacePPWhitespace(Tok, Newlines, Indent, PreviousEndOfLineColumn, Style,
SourceMgr, Replaces);
}
return Indent;
}
clang::DiagnosticsEngine &Diag;
FormatStyle Style;
Lexer &Lex;