]> granicus.if.org Git - clang/commitdiff
Skip over AnnotatedLines with >50 levels of nesting; don't format them.
authorDaniel Jasper <djasper@google.com>
Mon, 31 Oct 2016 13:23:00 +0000 (13:23 +0000)
committerDaniel Jasper <djasper@google.com>
Mon, 31 Oct 2016 13:23:00 +0000 (13:23 +0000)
Reasoning:
- ExpressionParser uses a lot of stack for these, bad in some environments.
- Our formatting algorithm is N^3 and gets really slow.
- The resulting formatting is unlikely to be any good.
- This is probably generated code we're formatting by accident.

We treat these as unparseable, and signal incomplete formatting. 50 is
an arbitrary number, I've only seen real problems from ~150 levels.

Patch by Sam McCall. Thank you.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@285570 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Format/TokenAnnotator.cpp
unittests/Format/FormatTest.cpp

index 9237fc6ec53c38ed784dc6688913cc3e670c4fac..1253e56c9867f921502a8adeba90f0b0ae8bcf3f 100644 (file)
@@ -1566,6 +1566,13 @@ void TokenAnnotator::setCommentLineLevels(
   }
 }
 
+static unsigned maxNestingDepth(const AnnotatedLine &Line) {
+  unsigned Result = 0;
+  for (const auto* Tok = Line.First; Tok != nullptr; Tok = Tok->Next)
+    Result = std::max(Result, Tok->NestingLevel);
+  return Result;
+}
+
 void TokenAnnotator::annotate(AnnotatedLine &Line) {
   for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(),
                                                   E = Line.Children.end();
@@ -1574,6 +1581,14 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
   }
   AnnotatingParser Parser(Style, Line, Keywords);
   Line.Type = Parser.parseLine();
+
+  // With very deep nesting, ExpressionParser uses lots of stack and the
+  // formatting algorithm is very slow. We're not going to do a good job here
+  // anyway - it's probably generated code being formatted by mistake.
+  // Just skip the whole line.
+  if (maxNestingDepth(Line) > 50)
+    Line.Type = LT_Invalid;
+
   if (Line.Type == LT_Invalid)
     return;
 
index ee08121c5ad80f10df9ad8a318fc27f871bd526f..b95a29f781c57fe53887082b8c70d3f73ee59580 100644 (file)
@@ -7179,6 +7179,30 @@ TEST_F(FormatTest, SpecialTokensAtEndOfLine) {
   verifyFormat("operator");
 }
 
+TEST_F(FormatTest, SkipsDeeplyNestedLines) {
+  // This code would be painfully slow to format if we didn't skip it.
+  std::string Code("A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n" // 20x
+                   "A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n"
+                   "A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n"
+                   "A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n"
+                   "A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(A(\n"
+                   "A(1, 1)\n"
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n" // 10x
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1)\n"
+                   ", 1), 1), 1), 1), 1), 1), 1), 1), 1), 1);\n");
+  // Deeply nested part is untouched, rest is formatted.
+  EXPECT_EQ(std::string("int i;\n") + Code + "int j;\n",
+            format(std::string("int    i;\n") + Code + "int    j;\n",
+                   getLLVMStyle(), IC_ExpectIncomplete));
+}
+
 //===----------------------------------------------------------------------===//
 // Objective-C tests.
 //===----------------------------------------------------------------------===//