forked from OSchip/llvm-project
Enables layouting unwrapped lines around preprocessor directives.
Previously, we'd always start at indent level 0 after a preprocessor directive, now we layout the following snippet (column limit 69) as follows: functionCallTo(someOtherFunction( withSomeParameters, whichInSequence, areLongerThanALine(andAnotherCall, B withMoreParamters, whichStronglyInfluenceTheLayout), andMoreParameters), trailing); Note that the different jumping indent is a different issue that will be addressed separately. This is the first step towards handling #ifdef->#else->#endif chains correctly. llvm-svn: 171974
This commit is contained in:
parent
864ef315c0
commit
52b1515405
|
@ -803,18 +803,21 @@ public:
|
||||||
void calculateExtraInformation(AnnotatedToken &Current) {
|
void calculateExtraInformation(AnnotatedToken &Current) {
|
||||||
Current.SpaceRequiredBefore = spaceRequiredBefore(Current);
|
Current.SpaceRequiredBefore = spaceRequiredBefore(Current);
|
||||||
|
|
||||||
if (Current.Type == TT_CtorInitializerColon || Current.Parent->Type ==
|
if (Current.FormatTok.MustBreakBefore) {
|
||||||
TT_LineComment || (Current.is(tok::string_literal) &&
|
|
||||||
Current.Parent->is(tok::string_literal))) {
|
|
||||||
Current.MustBreakBefore = true;
|
|
||||||
} else if (Current.is(tok::at) && Current.Parent->Parent->is(tok::at)) {
|
|
||||||
// Don't put two objc's '@' on the same line. This could happen,
|
|
||||||
// as in, @optional @property ...
|
|
||||||
Current.MustBreakBefore = true;
|
Current.MustBreakBefore = true;
|
||||||
} else {
|
} else {
|
||||||
Current.MustBreakBefore = false;
|
if (Current.Type == TT_CtorInitializerColon || Current.Parent->Type ==
|
||||||
|
TT_LineComment || (Current.is(tok::string_literal) &&
|
||||||
|
Current.Parent->is(tok::string_literal))) {
|
||||||
|
Current.MustBreakBefore = true;
|
||||||
|
} else if (Current.is(tok::at) && Current.Parent->Parent->is(tok::at)) {
|
||||||
|
// Don't put two objc's '@' on the same line. This could happen,
|
||||||
|
// as in, @optional @property ...
|
||||||
|
Current.MustBreakBefore = true;
|
||||||
|
} else {
|
||||||
|
Current.MustBreakBefore = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Current.CanBreakBefore = Current.MustBreakBefore || canBreakBefore(Current);
|
Current.CanBreakBefore = Current.MustBreakBefore || canBreakBefore(Current);
|
||||||
|
|
||||||
if (!Current.Children.empty())
|
if (!Current.Children.empty())
|
||||||
|
|
|
@ -74,8 +74,9 @@ private:
|
||||||
UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
|
UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
|
||||||
FormatTokenSource &Tokens,
|
FormatTokenSource &Tokens,
|
||||||
UnwrappedLineConsumer &Callback)
|
UnwrappedLineConsumer &Callback)
|
||||||
: RootTokenInitialized(false), Style(Style), Tokens(&Tokens),
|
: Line(new UnwrappedLine), RootTokenInitialized(false),
|
||||||
Callback(Callback) {
|
LastInCurrentLine(NULL), MustBreakBeforeNextToken(false), Style(Style),
|
||||||
|
Tokens(&Tokens), Callback(Callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnwrappedLineParser::parse() {
|
bool UnwrappedLineParser::parse() {
|
||||||
|
@ -126,9 +127,9 @@ bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
|
||||||
|
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
|
|
||||||
Line.Level += AddLevels;
|
Line->Level += AddLevels;
|
||||||
parseLevel(/*HasOpeningBrace=*/true);
|
parseLevel(/*HasOpeningBrace=*/true);
|
||||||
Line.Level -= AddLevels;
|
Line->Level -= AddLevels;
|
||||||
|
|
||||||
if (!FormatTok.Tok.is(tok::r_brace))
|
if (!FormatTok.Tok.is(tok::r_brace))
|
||||||
return true;
|
return true;
|
||||||
|
@ -139,7 +140,7 @@ bool UnwrappedLineParser::parseBlock(unsigned AddLevels) {
|
||||||
|
|
||||||
void UnwrappedLineParser::parsePPDirective() {
|
void UnwrappedLineParser::parsePPDirective() {
|
||||||
assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
|
assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
|
||||||
ScopedMacroState MacroState(Line, Tokens, FormatTok);
|
ScopedMacroState MacroState(*Line, Tokens, FormatTok);
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
if (FormatTok.Tok.getIdentifierInfo() == NULL) {
|
if (FormatTok.Tok.getIdentifierInfo() == NULL) {
|
||||||
|
@ -169,7 +170,7 @@ void UnwrappedLineParser::parsePPDefine() {
|
||||||
parseParens();
|
parseParens();
|
||||||
}
|
}
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
Line.Level = 1;
|
Line->Level = 1;
|
||||||
|
|
||||||
// Errors during a preprocessor directive can only affect the layout of the
|
// Errors during a preprocessor directive can only affect the layout of the
|
||||||
// preprocessor directive, and thus we ignore them. An alternative approach
|
// preprocessor directive, and thus we ignore them. An alternative approach
|
||||||
|
@ -319,9 +320,9 @@ void UnwrappedLineParser::parseIfThenElse() {
|
||||||
NeedsUnwrappedLine = true;
|
NeedsUnwrappedLine = true;
|
||||||
} else {
|
} else {
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
++Line.Level;
|
++Line->Level;
|
||||||
parseStructuralElement();
|
parseStructuralElement();
|
||||||
--Line.Level;
|
--Line->Level;
|
||||||
}
|
}
|
||||||
if (FormatTok.Tok.is(tok::kw_else)) {
|
if (FormatTok.Tok.is(tok::kw_else)) {
|
||||||
nextToken();
|
nextToken();
|
||||||
|
@ -332,9 +333,9 @@ void UnwrappedLineParser::parseIfThenElse() {
|
||||||
parseIfThenElse();
|
parseIfThenElse();
|
||||||
} else {
|
} else {
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
++Line.Level;
|
++Line->Level;
|
||||||
parseStructuralElement();
|
parseStructuralElement();
|
||||||
--Line.Level;
|
--Line->Level;
|
||||||
}
|
}
|
||||||
} else if (NeedsUnwrappedLine) {
|
} else if (NeedsUnwrappedLine) {
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
|
@ -363,9 +364,9 @@ void UnwrappedLineParser::parseForOrWhileLoop() {
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
} else {
|
} else {
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
++Line.Level;
|
++Line->Level;
|
||||||
parseStructuralElement();
|
parseStructuralElement();
|
||||||
--Line.Level;
|
--Line->Level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,9 +377,9 @@ void UnwrappedLineParser::parseDoWhile() {
|
||||||
parseBlock();
|
parseBlock();
|
||||||
} else {
|
} else {
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
++Line.Level;
|
++Line->Level;
|
||||||
parseStructuralElement();
|
parseStructuralElement();
|
||||||
--Line.Level;
|
--Line->Level;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Add error handling.
|
// FIXME: Add error handling.
|
||||||
|
@ -395,14 +396,14 @@ void UnwrappedLineParser::parseLabel() {
|
||||||
// FIXME: remove all asserts.
|
// FIXME: remove all asserts.
|
||||||
assert(FormatTok.Tok.is(tok::colon) && "':' expected");
|
assert(FormatTok.Tok.is(tok::colon) && "':' expected");
|
||||||
nextToken();
|
nextToken();
|
||||||
unsigned OldLineLevel = Line.Level;
|
unsigned OldLineLevel = Line->Level;
|
||||||
if (Line.Level > 0)
|
if (Line->Level > 0)
|
||||||
--Line.Level;
|
--Line->Level;
|
||||||
if (FormatTok.Tok.is(tok::l_brace)) {
|
if (FormatTok.Tok.is(tok::l_brace)) {
|
||||||
parseBlock();
|
parseBlock();
|
||||||
}
|
}
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
Line.Level = OldLineLevel;
|
Line->Level = OldLineLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnwrappedLineParser::parseCaseLabel() {
|
void UnwrappedLineParser::parseCaseLabel() {
|
||||||
|
@ -423,9 +424,9 @@ void UnwrappedLineParser::parseSwitch() {
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
} else {
|
} else {
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
Line.Level += (Style.IndentCaseLabels ? 2 : 1);
|
Line->Level += (Style.IndentCaseLabels ? 2 : 1);
|
||||||
parseStructuralElement();
|
parseStructuralElement();
|
||||||
Line.Level -= (Style.IndentCaseLabels ? 2 : 1);
|
Line->Level -= (Style.IndentCaseLabels ? 2 : 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,7 +445,7 @@ void UnwrappedLineParser::parseEnum() {
|
||||||
case tok::l_brace:
|
case tok::l_brace:
|
||||||
nextToken();
|
nextToken();
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
++Line.Level;
|
++Line->Level;
|
||||||
parseComments();
|
parseComments();
|
||||||
break;
|
break;
|
||||||
case tok::l_paren:
|
case tok::l_paren:
|
||||||
|
@ -458,7 +459,7 @@ void UnwrappedLineParser::parseEnum() {
|
||||||
case tok::r_brace:
|
case tok::r_brace:
|
||||||
if (HasContents)
|
if (HasContents)
|
||||||
addUnwrappedLine();
|
addUnwrappedLine();
|
||||||
--Line.Level;
|
--Line->Level;
|
||||||
nextToken();
|
nextToken();
|
||||||
break;
|
break;
|
||||||
case tok::semi:
|
case tok::semi:
|
||||||
|
@ -501,8 +502,9 @@ void UnwrappedLineParser::addUnwrappedLine() {
|
||||||
FormatTok.Tok.is(tok::comment)) {
|
FormatTok.Tok.is(tok::comment)) {
|
||||||
nextToken();
|
nextToken();
|
||||||
}
|
}
|
||||||
Callback.consumeUnwrappedLine(Line);
|
Callback.consumeUnwrappedLine(*Line);
|
||||||
RootTokenInitialized = false;
|
RootTokenInitialized = false;
|
||||||
|
LastInCurrentLine = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnwrappedLineParser::eof() const {
|
bool UnwrappedLineParser::eof() const {
|
||||||
|
@ -513,26 +515,42 @@ void UnwrappedLineParser::nextToken() {
|
||||||
if (eof())
|
if (eof())
|
||||||
return;
|
return;
|
||||||
if (RootTokenInitialized) {
|
if (RootTokenInitialized) {
|
||||||
|
assert(LastInCurrentLine->Children.empty());
|
||||||
LastInCurrentLine->Children.push_back(FormatTok);
|
LastInCurrentLine->Children.push_back(FormatTok);
|
||||||
LastInCurrentLine = &LastInCurrentLine->Children.back();
|
LastInCurrentLine = &LastInCurrentLine->Children.back();
|
||||||
} else {
|
} else {
|
||||||
Line.RootToken = FormatTok;
|
Line->RootToken = FormatTok;
|
||||||
RootTokenInitialized = true;
|
RootTokenInitialized = true;
|
||||||
LastInCurrentLine = &Line.RootToken;
|
LastInCurrentLine = &Line->RootToken;
|
||||||
|
}
|
||||||
|
if (MustBreakBeforeNextToken) {
|
||||||
|
LastInCurrentLine->MustBreakBefore = true;
|
||||||
|
MustBreakBeforeNextToken = false;
|
||||||
}
|
}
|
||||||
readToken();
|
readToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnwrappedLineParser::readToken() {
|
void UnwrappedLineParser::readToken() {
|
||||||
FormatTok = Tokens->getNextToken();
|
FormatTok = Tokens->getNextToken();
|
||||||
while (!Line.InPPDirective && FormatTok.Tok.is(tok::hash) &&
|
while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) &&
|
||||||
((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
|
((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
|
||||||
FormatTok.IsFirst)) {
|
FormatTok.IsFirst)) {
|
||||||
// FIXME: This is incorrect - the correct way is to create a
|
UnwrappedLine* StoredLine = Line.take();
|
||||||
// data structure that will construct the parts around the preprocessor
|
Line.reset(new UnwrappedLine(*StoredLine));
|
||||||
// directive as a structured \c UnwrappedLine.
|
assert(LastInCurrentLine == NULL || LastInCurrentLine->Children.empty());
|
||||||
addUnwrappedLine();
|
FormatToken *StoredLastInCurrentLine = LastInCurrentLine;
|
||||||
|
bool PreviousInitialized = RootTokenInitialized;
|
||||||
|
RootTokenInitialized = false;
|
||||||
|
LastInCurrentLine = NULL;
|
||||||
|
|
||||||
parsePPDirective();
|
parsePPDirective();
|
||||||
|
|
||||||
|
assert(!RootTokenInitialized);
|
||||||
|
Line.reset(StoredLine);
|
||||||
|
RootTokenInitialized = PreviousInitialized;
|
||||||
|
LastInCurrentLine = StoredLastInCurrentLine;
|
||||||
|
assert(LastInCurrentLine == NULL || LastInCurrentLine->Children.empty());
|
||||||
|
MustBreakBeforeNextToken = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace format {
|
||||||
struct FormatToken {
|
struct FormatToken {
|
||||||
FormatToken()
|
FormatToken()
|
||||||
: NewlinesBefore(0), HasUnescapedNewline(false), WhiteSpaceLength(0),
|
: NewlinesBefore(0), HasUnescapedNewline(false), WhiteSpaceLength(0),
|
||||||
TokenLength(0), IsFirst(false) {
|
TokenLength(0), IsFirst(false), MustBreakBefore(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief The \c Token.
|
/// \brief The \c Token.
|
||||||
|
@ -68,6 +68,12 @@ struct FormatToken {
|
||||||
/// \brief Indicates that this is the first token.
|
/// \brief Indicates that this is the first token.
|
||||||
bool IsFirst;
|
bool IsFirst;
|
||||||
|
|
||||||
|
/// \brief Whether there must be a line break before this token.
|
||||||
|
///
|
||||||
|
/// This happens for example when a preprocessor directive ended directly
|
||||||
|
/// before the token.
|
||||||
|
bool MustBreakBefore;
|
||||||
|
|
||||||
// FIXME: We currently assume that there is exactly one token in this vector
|
// FIXME: We currently assume that there is exactly one token in this vector
|
||||||
// except for the very last token that does not have any children.
|
// except for the very last token that does not have any children.
|
||||||
/// \brief All tokens that logically follow this token.
|
/// \brief All tokens that logically follow this token.
|
||||||
|
@ -144,10 +150,11 @@ private:
|
||||||
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
|
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
|
||||||
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
|
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
|
||||||
// and use that everywhere in the Parser.
|
// and use that everywhere in the Parser.
|
||||||
UnwrappedLine Line;
|
llvm::OwningPtr<UnwrappedLine> Line;
|
||||||
bool RootTokenInitialized;
|
bool RootTokenInitialized;
|
||||||
FormatToken *LastInCurrentLine;
|
FormatToken *LastInCurrentLine;
|
||||||
FormatToken FormatTok;
|
FormatToken FormatTok;
|
||||||
|
bool MustBreakBeforeNextToken;
|
||||||
|
|
||||||
const FormatStyle &Style;
|
const FormatStyle &Style;
|
||||||
FormatTokenSource *Tokens;
|
FormatTokenSource *Tokens;
|
||||||
|
|
|
@ -46,17 +46,24 @@ protected:
|
||||||
std::string messUp(llvm::StringRef Code) {
|
std::string messUp(llvm::StringRef Code) {
|
||||||
std::string MessedUp(Code.str());
|
std::string MessedUp(Code.str());
|
||||||
bool InComment = false;
|
bool InComment = false;
|
||||||
|
bool InPreprocessorDirective = false;
|
||||||
bool JustReplacedNewline = false;
|
bool JustReplacedNewline = false;
|
||||||
for (unsigned i = 0, e = MessedUp.size() - 1; i != e; ++i) {
|
for (unsigned i = 0, e = MessedUp.size() - 1; i != e; ++i) {
|
||||||
if (MessedUp[i] == '/' && MessedUp[i + 1] == '/') {
|
if (MessedUp[i] == '/' && MessedUp[i + 1] == '/') {
|
||||||
if (JustReplacedNewline)
|
if (JustReplacedNewline)
|
||||||
MessedUp[i - 1] = '\n';
|
MessedUp[i - 1] = '\n';
|
||||||
InComment = true;
|
InComment = true;
|
||||||
|
} else if (MessedUp[i] == '#' && JustReplacedNewline) {
|
||||||
|
MessedUp[i - 1] = '\n';
|
||||||
|
InPreprocessorDirective = true;
|
||||||
} else if (MessedUp[i] == '\\' && MessedUp[i + 1] == '\n') {
|
} else if (MessedUp[i] == '\\' && MessedUp[i + 1] == '\n') {
|
||||||
MessedUp[i] = ' ';
|
MessedUp[i] = ' ';
|
||||||
|
MessedUp[i + 1] = ' ';
|
||||||
} else if (MessedUp[i] == '\n') {
|
} else if (MessedUp[i] == '\n') {
|
||||||
if (InComment) {
|
if (InComment) {
|
||||||
InComment = false;
|
InComment = false;
|
||||||
|
} else if (InPreprocessorDirective) {
|
||||||
|
InPreprocessorDirective = false;
|
||||||
} else {
|
} else {
|
||||||
JustReplacedNewline = true;
|
JustReplacedNewline = true;
|
||||||
MessedUp[i] = ' ';
|
MessedUp[i] = ' ';
|
||||||
|
@ -84,6 +91,14 @@ protected:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TEST_F(FormatTest, MessUp) {
|
||||||
|
EXPECT_EQ("1 2 3", messUp("1 2 3"));
|
||||||
|
EXPECT_EQ("1 2 3\n", messUp("1\n2\n3\n"));
|
||||||
|
EXPECT_EQ("a\n//b\nc", messUp("a\n//b\nc"));
|
||||||
|
EXPECT_EQ("a\n#b\nc", messUp("a\n#b\nc"));
|
||||||
|
EXPECT_EQ("a\n#b c d\ne", messUp("a\n#b\\\nc\\\nd\ne"));
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Basic function tests.
|
// Basic function tests.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -545,7 +560,9 @@ TEST_F(FormatTest, LayoutSingleUnwrappedLineInMacro) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FormatTest, MacroDefinitionInsideStatement) {
|
TEST_F(FormatTest, MacroDefinitionInsideStatement) {
|
||||||
EXPECT_EQ("int x,\n#define A\ny;", format("int x,\n#define A\ny;"));
|
EXPECT_EQ("int x,\n"
|
||||||
|
"#define A\n"
|
||||||
|
" y;", format("int x,\n#define A\ny;"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FormatTest, HashInMacroDefinition) {
|
TEST_F(FormatTest, HashInMacroDefinition) {
|
||||||
|
@ -609,6 +626,23 @@ TEST_F(FormatTest, MixingPreprocessorDirectivesAndNormalCode) {
|
||||||
" aLooooooooooooooooooooooonPaaaaaaaaaaaaaaaaaaaaarmmmm);\n"));
|
" aLooooooooooooooooooooooonPaaaaaaaaaaaaaaaaaaaaarmmmm);\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(FormatTest, LayoutStatementsAroundPreprocessorDirectives) {
|
||||||
|
EXPECT_EQ("int\n"
|
||||||
|
"#define A\n"
|
||||||
|
" a;",
|
||||||
|
format("int\n#define A\na;"));
|
||||||
|
verifyFormat(
|
||||||
|
"functionCallTo(someOtherFunction(\n"
|
||||||
|
" withSomeParameters, whichInSequence,\n"
|
||||||
|
" areLongerThanALine(andAnotherCall,\n"
|
||||||
|
"#define A \\\n"
|
||||||
|
" B\n"
|
||||||
|
" withMoreParamters,\n"
|
||||||
|
" whichStronglyInfluenceTheLayout),\n"
|
||||||
|
" andMoreParameters),\n"
|
||||||
|
" trailing);", getLLVMStyleWithColumns(69));
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Line break tests.
|
// Line break tests.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
Loading…
Reference in New Issue