aboutsummaryrefslogtreecommitdiff
path: root/lib/Format/TokenAnnotator.cpp
diff options
context:
space:
mode:
authorDaniel Jasper <djasper@google.com>2013-02-08 15:28:42 +0000
committerDaniel Jasper <djasper@google.com>2013-02-08 15:28:42 +0000
commit29f123b2fa0435bb1962f0d9e9a2e660f35fbb2f (patch)
tree0cb3048ca2251ae5b6faa28dfea86f1612e72217 /lib/Format/TokenAnnotator.cpp
parentce3d1a68d98f8a557ba5a5391cae8278ae6f29d2 (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.cpp96
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;