Fix formatting of preprocessor directives (incluces, warnings & errors).
authorManuel Klimek <klimek@google.com>
Tue, 15 Jan 2013 15:50:27 +0000 (15:50 +0000)
committerManuel Klimek <klimek@google.com>
Tue, 15 Jan 2013 15:50:27 +0000 (15:50 +0000)
Treat tokens inside <> for includes and everything from the second token
of a warning / error on as an implicit string literal, e.g. do not
change its whitespace at all.

Now correctly formats:
 #include < path with space >
 #error Leave     all         white!!!!! space* alone!

Note that for #error and #warning we still format the space up to the
first token of the text, so:
   #  error   Text
will become
 #error Text

llvm-svn: 172536

clang/lib/Format/Format.cpp
clang/unittests/Format/FormatTest.cpp

index c40aa53..a6b9e20 100644 (file)
@@ -34,7 +34,7 @@ enum TokenType {
   TT_CastRParen,
   TT_ConditionalExpr,
   TT_CtorInitializerColon,
-  TT_IncludePath,
+  TT_ImplicitStringLiteral,
   TT_LineComment,
   TT_ObjCBlockLParen,
   TT_ObjCDecl,
@@ -374,6 +374,11 @@ private:
     assert(State.Stack.size());
     unsigned ParenLevel = State.Stack.size() - 1;
 
+    if (Current.Type == TT_ImplicitStringLiteral) {
+      moveStateToNextToken(State);
+      return;
+    }
+
     if (Newline) {
       unsigned WhitespaceStartColumn = State.Column;
       if (Current.is(tok::r_brace)) {
@@ -862,8 +867,27 @@ public:
     }
 
     void parseIncludeDirective() {
+      next();
+      if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
+        next();
+        while (CurrentToken != NULL) {
+          CurrentToken->Type = TT_ImplicitStringLiteral;
+          next();
+        }
+      } else {
+        while (CurrentToken != NULL) {
+          next();
+        }
+      }
+    }
+
+    void parseWarningOrError() {
+      next();
+      // We still want to format the whitespace left of the first token of the
+      // warning or error.
+      next();
       while (CurrentToken != NULL) {
-        CurrentToken->Type = TT_IncludePath;
+        CurrentToken->Type = TT_ImplicitStringLiteral;
         next();
       }
     }
@@ -882,6 +906,10 @@ public:
       case tok::pp_import:
         parseIncludeDirective();
         break;
+      case tok::pp_error:
+      case tok::pp_warning:
+        parseWarningOrError();
+        break;
       default:
         break;
       }
@@ -1213,8 +1241,6 @@ private:
 
     if (Tok.Parent->is(tok::comma))
       return true;
-    if (Tok.Type == TT_IncludePath)
-      return Tok.is(tok::less) || Tok.is(tok::string_literal);
     if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
       return true;
     if (Tok.Type == TT_OverloadedOperator)
@@ -1264,8 +1290,6 @@ private:
         // Don't break at ':' if identifier before it can beak.
         return false;
     }
-    if (Right.Type == TT_IncludePath)
-      return false;
     if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
       return false;
     if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
index c6f1c8e..eb00d01 100644 (file)
@@ -1184,7 +1184,8 @@ TEST_F(FormatTest, HandlesIncludeDirectives) {
                "#include \"a/b/string\"\n"
                "#include \"string.h\"\n"
                "#include \"string.h\"\n"
-               "#include <a-a>");
+               "#include <a-a>\n"
+               "#include < path with space >\n");
 
   verifyFormat("#import <string>");
   verifyFormat("#import <a/b/c.h>");
@@ -1334,6 +1335,13 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
                "  f();\n");
 }
 
+TEST_F(FormatTest, DoNotInterfereWithErrorAndWarning) {
+  verifyFormat("#error Leave     all         white!!!!! space* alone!\n");
+  verifyFormat("#warning Leave     all         white!!!!! space* alone!\n");
+  EXPECT_EQ("#error 1", format("  #  error   1"));
+  EXPECT_EQ("#warning 1", format("  #  warning 1"));
+}
+
 // FIXME: This breaks the order of the unwrapped lines:
 // TEST_F(FormatTest, OrderUnwrappedLines) {
 //   verifyFormat("{\n"