[clang-scan-deps] Allow continuation line backslashes followed by whitespace
authorAlex Lorenz <arphaman@gmail.com>
Thu, 26 Sep 2019 19:28:51 +0000 (19:28 +0000)
committerAlex Lorenz <arphaman@gmail.com>
Thu, 26 Sep 2019 19:28:51 +0000 (19:28 +0000)
in the dependency source minimizer

Clang allows continuations that have whitespace between the backslash and the newline.
This patch ensures that the dependency source minimizer can handle the whitespace between
the backslash and the newline when looking for a line continuation.

Differential Revision: https://reviews.llvm.org/D68052

llvm-svn: 373007

clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
clang/unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp

index 2a3c882..2ffbcfb 100644 (file)
@@ -244,14 +244,20 @@ static void skipToNewlineRaw(const char *&First, const char *const End) {
   }
 }
 
-static const char *reverseOverSpaces(const char *First, const char *Last) {
+static const char *findLastNonSpace(const char *First, const char *Last) {
   assert(First <= Last);
-  const char *PrevLast = Last;
-  while (First != Last && isHorizontalWhitespace(Last[-1])) {
-    PrevLast = Last;
+  while (First != Last && isHorizontalWhitespace(Last[-1]))
     --Last;
-  }
-  return PrevLast;
+  return Last;
+}
+
+static const char *findFirstTrailingSpace(const char *First,
+                                          const char *Last) {
+  const char *LastNonSpace = findLastNonSpace(First, Last);
+  if (Last == LastNonSpace)
+    return Last;
+  assert(isHorizontalWhitespace(LastNonSpace[0]));
+  return LastNonSpace + 1;
 }
 
 static void skipLineComment(const char *&First, const char *const End) {
@@ -385,7 +391,7 @@ void Minimizer::printToNewline(const char *&First, const char *const End) {
       }
 
       // Deal with "//..." and "/*...*/".
-      append(First, reverseOverSpaces(First, Last));
+      append(First, findFirstTrailingSpace(First, Last));
       First = Last;
 
       if (Last[1] == '/') {
@@ -400,15 +406,20 @@ void Minimizer::printToNewline(const char *&First, const char *const End) {
     } while (Last != End && !isVerticalWhitespace(*Last));
 
     // Print out the string.
-    if (Last == End || Last == First || Last[-1] != '\\') {
-      append(First, reverseOverSpaces(First, Last));
+    const char *LastBeforeTrailingSpace = findLastNonSpace(First, Last);
+    if (Last == End || LastBeforeTrailingSpace == First ||
+        LastBeforeTrailingSpace[-1] != '\\') {
+      append(First, LastBeforeTrailingSpace);
       First = Last;
       skipNewline(First, End);
       return;
     }
 
-    // Print up to the backslash, backing up over spaces.
-    append(First, reverseOverSpaces(First, Last - 1));
+    // Print up to the backslash, backing up over spaces. Preserve at least one
+    // space, as the space matters when tokens are separated by a line
+    // continuation.
+    append(First, findFirstTrailingSpace(
+                      First, LastBeforeTrailingSpace - 1));
 
     First = Last;
     skipNewline(First, End);
index c00c160..5eb7d25 100644 (file)
@@ -157,19 +157,19 @@ TEST(MinimizeSourceToDependencyDirectivesTest, DefineHorizontalWhitespace) {
 
   ASSERT_FALSE(minimizeSourceToDependencyDirectives(
       "#define MACRO(\t)\tcon \t tent\t", Out));
-  EXPECT_STREQ("#define MACRO() con \t tent\t\n", Out.data());
+  EXPECT_STREQ("#define MACRO() con \t tent\n", Out.data());
 
   ASSERT_FALSE(minimizeSourceToDependencyDirectives(
       "#define MACRO(\f)\fcon \f tent\f", Out));
-  EXPECT_STREQ("#define MACRO() con \f tent\f\n", Out.data());
+  EXPECT_STREQ("#define MACRO() con \f tent\n", Out.data());
 
   ASSERT_FALSE(minimizeSourceToDependencyDirectives(
       "#define MACRO(\v)\vcon \v tent\v", Out));
-  EXPECT_STREQ("#define MACRO() con \v tent\v\n", Out.data());
+  EXPECT_STREQ("#define MACRO() con \v tent\n", Out.data());
 
   ASSERT_FALSE(minimizeSourceToDependencyDirectives(
       "#define MACRO \t\v\f\v\t con\f\t\vtent\v\f \v", Out));
-  EXPECT_STREQ("#define MACRO con\f\t\vtent\v\n", Out.data());
+  EXPECT_STREQ("#define MACRO con\f\t\vtent\n", Out.data());
 }
 
 TEST(MinimizeSourceToDependencyDirectivesTest, DefineMultilineArgs) {
@@ -476,6 +476,17 @@ TEST(MinimizeSourceToDependencyDirectivesTest, SplitIdentifier) {
   EXPECT_STREQ("#define GUA RD\n", Out.data());
 }
 
+TEST(MinimizeSourceToDependencyDirectivesTest,
+     WhitespaceAfterLineContinuationSlash) {
+  SmallVector<char, 128> Out;
+
+  ASSERT_FALSE(minimizeSourceToDependencyDirectives("#define A 1 + \\  \n"
+                                                    "2 + \\\t\n"
+                                                    "3\n",
+                                                    Out));
+  EXPECT_STREQ("#define A 1 + 2 + 3\n", Out.data());
+}
+
 TEST(MinimizeSourceToDependencyDirectivesTest, PoundWarningAndError) {
   SmallVector<char, 128> Out;