diff options
author | Daniel Jasper <djasper@google.com> | 2013-02-08 15:28:42 +0000 |
---|---|---|
committer | Daniel Jasper <djasper@google.com> | 2013-02-08 15:28:42 +0000 |
commit | 29f123b2fa0435bb1962f0d9e9a2e660f35fbb2f (patch) | |
tree | 0cb3048ca2251ae5b6faa28dfea86f1612e72217 /lib/Format/TokenAnnotator.cpp | |
parent | ce3d1a68d98f8a557ba5a5391cae8278ae6f29d2 (diff) |
Implement a tiny expression parser to improve formatting decisions.
With this patch, the formatter introduces 'fake' parenthesis according
to the operator precedence of binary operators.
Before:
return aaaa & AAAAAAAAAAAAAAAAAAAAAAAAAAAAA || bbbb &
BBBBBBBBBBBBBBBBBBBBBBBBBBBBB || cccc & CCCCCCCCCCCCCCCCCCCCCCCCCC ||
dddd & DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD;
f(aaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa &&
aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaa);
After:
return aaaa & AAAAAAAAAAAAAAAAAAAAAAAAAAAAA ||
bbbb & BBBBBBBBBBBBBBBBBBBBBBBBBBBBB ||
cccc & CCCCCCCCCCCCCCCCCCCCCCCCCC ||
dddd & DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD;
f(aaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaa,
aaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaa,
aaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaa);
Future improvements:
- Get rid of some of the hacky ways to nicely format certain constructs.
- Merge this parser and the AnnotatingParser as we now have several parsers
that analyze (), [], etc.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174714 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Format/TokenAnnotator.cpp')
-rw-r--r-- | lib/Format/TokenAnnotator.cpp | 96 |
1 files changed, 90 insertions, 6 deletions
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 8a384540d8..485624b7fa 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -52,6 +52,12 @@ static const AnnotatedToken *getPreviousToken(const AnnotatedToken &Tok) { return getPreviousToken(const_cast<AnnotatedToken &>(Tok)); } +static bool isTrailingComment(AnnotatedToken *Tok) { + return Tok != NULL && Tok->is(tok::comment) && + (Tok->Children.empty() || + Tok->Children[0].FormatTok.NewlinesBefore > 0); +} + // Returns the next token ignoring comments. static const AnnotatedToken *getNextToken(const AnnotatedToken &Tok) { if (Tok.Children.empty()) @@ -681,12 +687,91 @@ private: bool KeywordVirtualFound; }; +/// \brief Parses binary expressions by inserting fake parenthesis based on +/// operator precedence. +class ExpressionParser { +public: + ExpressionParser(AnnotatedLine &Line) : Current(&Line.First) {} + + /// \brief Parse expressions with the given operatore precedence. + void parse(unsigned Precedence = prec::Unknown) { + if (Precedence > prec::PointerToMember || Current == NULL) + return; + + // Skip over "return" until we can properly parse it. + if (Current->is(tok::kw_return)) + next(); + + // Eagerly consume trailing comments. + while (isTrailingComment(Current)) { + next(); + } + + AnnotatedToken *Start = Current; + bool OperatorFound = false; + + while (Current != NULL) { + // Consume operators with higher precedence. + parse(Precedence + 1); + + // At the end of the line or when an operator with higher precedence is + // found, insert fake parenthesis and return. + if (Current == NULL || Current->is(tok::semi) || closesScope(*Current) || + ((Current->Type == TT_BinaryOperator || Current->is(tok::comma)) && + getPrecedence(*Current) < Precedence)) { + if (OperatorFound) { + ++Start->FakeLParens; + if (Current != NULL) + ++Current->FakeRParens; + } + return; + } + + // Consume scopes: (), [], <> and {} + if (opensScope(*Current)) { + while (Current != NULL && !closesScope(*Current)) { + next(); + parse(); + } + next(); + } else { + // Operator found. + if (getPrecedence(*Current) == Precedence) + OperatorFound = true; + + next(); + } + } + } + +private: + void next() { + if (Current != NULL) + Current = Current->Children.empty() ? NULL : &Current->Children[0]; + } + + bool closesScope(const AnnotatedToken &Tok) { + return Current->is(tok::r_paren) || Current->Type == TT_TemplateCloser || + Current->is(tok::r_brace) || Current->is(tok::r_square); + } + + bool opensScope(const AnnotatedToken &Tok) { + return Current->is(tok::l_paren) || Current->Type == TT_TemplateOpener || + Current->is(tok::l_brace) || Current->is(tok::l_square); + } + + AnnotatedToken *Current; +}; + void TokenAnnotator::annotate(AnnotatedLine &Line) { AnnotatingParser Parser(SourceMgr, Lex, Line); Line.Type = Parser.parseLine(); if (Line.Type == LT_Invalid) return; + ExpressionParser ExprParser(Line); + ExprParser.parse(); + if (Line.First.Type == TT_ObjCMethodSpecifier) Line.Type = LT_ObjCMethodDecl; else if (Line.First.Type == TT_ObjCDecl) @@ -712,8 +797,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { Current->MustBreakBefore = true; } else if (Current->Type == TT_LineComment) { Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0; - } else if ((Current->Parent->is(tok::comment) && - Current->FormatTok.NewlinesBefore > 0) || + } else if (isTrailingComment(Current->Parent) || (Current->is(tok::string_literal) && Current->Parent->is(tok::string_literal))) { Current->MustBreakBefore = true; @@ -839,8 +923,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, (Left.isNot(tok::star) && Left.isNot(tok::amp) && !Style.PointerBindsToType); if (Left.is(tok::amp) || Left.is(tok::star)) - return Right.FormatTok.Tok.isLiteral() || - Style.PointerBindsToType; + return Right.FormatTok.Tok.isLiteral() || Style.PointerBindsToType; if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; if (Left.is(tok::l_square) || Right.is(tok::r_square)) @@ -911,8 +994,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, (Tok.Parent->isNot(tok::colon) || Tok.Parent->Type != TT_ObjCMethodExpr); if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) { - return Tok.Type == TT_TemplateCloser && Tok.Parent->Type == - TT_TemplateCloser && Style.Standard != FormatStyle::LS_Cpp11; + return Tok.Type == TT_TemplateCloser && + Tok.Parent->Type == TT_TemplateCloser && + Style.Standard != FormatStyle::LS_Cpp11; } if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator) return true; |