[clang] 9d49b82 - [clang-scan-deps] Implement P2223R2 for DependencyDirectiveScanner.cpp (#143950)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 13 10:48:08 PDT 2025
Author: Naveen Seth Hanig
Date: 2025-06-13T10:48:05-07:00
New Revision: 9d49b82de077c730d687593604dfa00770f11965
URL: https://github.com/llvm/llvm-project/commit/9d49b82de077c730d687593604dfa00770f11965
DIFF: https://github.com/llvm/llvm-project/commit/9d49b82de077c730d687593604dfa00770f11965.diff
LOG: [clang-scan-deps] Implement P2223R2 for DependencyDirectiveScanner.cpp (#143950)
P2223R2 allows the line-continuation slash `\` to be followed by
additional whitespace. The Clang lexer already follows this behavior,
also for versions prior to C++23. The dependency directive scanner
however only implements it for `#define` directives (15d5f5d).
This fully implements P2223R2 for the dependency directive scanner (for
any C++ standard) and aligns the dependency directive scanner's splicing
behavior with that of the Clang lexer.
For example, the following code was previously not scanned correctly by
`clang-scan-deps` but now works as expected:
```cpp
import \<whitespace here>
A;
```
Added:
Modified:
clang/lib/Lex/DependencyDirectivesScanner.cpp
clang/unittests/Lex/DependencyDirectivesScannerTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp
index 4606b85d42fe7..1b6b16c561141 100644
--- a/clang/lib/Lex/DependencyDirectivesScanner.cpp
+++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp
@@ -323,10 +323,6 @@ static unsigned skipNewline(const char *&First, const char *End) {
return Len;
}
-static bool wasLineContinuation(const char *First, unsigned EOLLen) {
- return *(First - (int)EOLLen - 1) == '\\';
-}
-
static void skipToNewlineRaw(const char *&First, const char *const End) {
for (;;) {
if (First == End)
@@ -336,13 +332,16 @@ static void skipToNewlineRaw(const char *&First, const char *const End) {
if (Len)
return;
+ char LastNonWhitespace = ' ';
do {
+ if (!isHorizontalWhitespace(*First))
+ LastNonWhitespace = *First;
if (++First == End)
return;
Len = isEOL(First, End);
} while (!Len);
- if (First[-1] != '\\')
+ if (LastNonWhitespace != '\\')
return;
First += Len;
@@ -394,6 +393,7 @@ static bool isQuoteCppDigitSeparator(const char *const Start,
}
void Scanner::skipLine(const char *&First, const char *const End) {
+ char LastNonWhitespace = ' ';
for (;;) {
assert(First <= End);
if (First == End)
@@ -419,6 +419,8 @@ void Scanner::skipLine(const char *&First, const char *const End) {
// Iterate over comments correctly.
if (*First != '/' || End - First < 2) {
LastTokenPtr = First;
+ if (!isWhitespace(*First))
+ LastNonWhitespace = *First;
++First;
continue;
}
@@ -431,6 +433,8 @@ void Scanner::skipLine(const char *&First, const char *const End) {
if (First[1] != '*') {
LastTokenPtr = First;
+ if (!isWhitespace(*First))
+ LastNonWhitespace = *First;
++First;
continue;
}
@@ -442,8 +446,9 @@ void Scanner::skipLine(const char *&First, const char *const End) {
return;
// Skip over the newline.
- unsigned Len = skipNewline(First, End);
- if (!wasLineContinuation(First, Len)) // Continue past line-continuations.
+ skipNewline(First, End);
+
+ if (LastNonWhitespace != '\\')
break;
}
}
@@ -468,9 +473,16 @@ static void skipWhitespace(const char *&First, const char *const End) {
if (End - First < 2)
return;
- if (First[0] == '\\' && isVerticalWhitespace(First[1])) {
- skipNewline(++First, End);
- continue;
+ if (*First == '\\') {
+ const char *Ptr = First + 1;
+ while (Ptr < End && isHorizontalWhitespace(*Ptr))
+ ++Ptr;
+ if (Ptr != End && isVerticalWhitespace(*Ptr)) {
+ skipNewline(Ptr, End);
+ First = Ptr;
+ continue;
+ }
+ return;
}
// Check for a non-comment character.
diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp
index 377c066f031d3..61f74929c1e98 100644
--- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp
+++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp
@@ -789,6 +789,97 @@ TEST(MinimizeSourceToDependencyDirectivesTest,
Out.data());
}
+TEST(MinimizeSourceToDependencyDirectivesTest,
+ WhitespaceAfterLineContinuationSlashLineComment) {
+ SmallVector<char, 128> Out;
+
+ ASSERT_FALSE(minimizeSourceToDependencyDirectives("// some comment \\ \n"
+ "module A;\n",
+ Out));
+ EXPECT_STREQ("", Out.data());
+}
+
+TEST(MinimizeSourceToDependencyDirectivesTest,
+ WhitespaceAfterLineContinuationSlashAllDirectives) {
+ SmallVector<char, 512> Out;
+ SmallVector<dependency_directives_scan::Token, 16> Tokens;
+ SmallVector<Directive, 16> Directives;
+
+ StringRef Input = "#define \\ \n"
+ "A\n"
+ "#undef\t\\ \n"
+ "A\n"
+ "#endif \\\t\t\n"
+ "\n"
+ "#if \\ \t\n"
+ "A\n"
+ "#ifdef\t\\ \n"
+ "A\n"
+ "#ifndef \\ \t\n"
+ "A\n"
+ "#elifdef \\ \n"
+ "A\n"
+ "#elifndef \\ \n"
+ "A\n"
+ "#elif \\\t\t \n"
+ "A\n"
+ "#else \\\t \t\n"
+ "\n"
+ "#include \\ \n"
+ "<A>\n"
+ "#include_next \\ \n"
+ "<A>\n"
+ "#__include_macros\\ \n"
+ "<A>\n"
+ "#import \\ \t\n"
+ "<A>\n"
+ "@import \\\t \n"
+ "A;\n"
+ "#pragma clang \\ \n"
+ "module \\ \n"
+ "import A\n"
+ "#pragma \\ \n"
+ "push_macro(A)\n"
+ "#pragma \\\t \n"
+ "pop_macro(A)\n"
+ "#pragma \\ \n"
+ "include_alias(<A>,\\ \n"
+ "<B>)\n"
+ "export \\ \n"
+ "module m;\n"
+ "import\t\\\t \n"
+ "m;\n"
+ "#pragma\t\\ \n"
+ "clang\t\\ \t\n"
+ "system_header\n";
+ ASSERT_FALSE(
+ minimizeSourceToDependencyDirectives(Input, Out, Tokens, Directives));
+
+ EXPECT_EQ(pp_define, Directives[0].Kind);
+ EXPECT_EQ(pp_undef, Directives[1].Kind);
+ EXPECT_EQ(pp_endif, Directives[2].Kind);
+ EXPECT_EQ(pp_if, Directives[3].Kind);
+ EXPECT_EQ(pp_ifdef, Directives[4].Kind);
+ EXPECT_EQ(pp_ifndef, Directives[5].Kind);
+ EXPECT_EQ(pp_elifdef, Directives[6].Kind);
+ EXPECT_EQ(pp_elifndef, Directives[7].Kind);
+ EXPECT_EQ(pp_elif, Directives[8].Kind);
+ EXPECT_EQ(pp_else, Directives[9].Kind);
+ EXPECT_EQ(pp_include, Directives[10].Kind);
+ EXPECT_EQ(pp_include_next, Directives[11].Kind);
+ EXPECT_EQ(pp___include_macros, Directives[12].Kind);
+ EXPECT_EQ(pp_import, Directives[13].Kind);
+ EXPECT_EQ(decl_at_import, Directives[14].Kind);
+ EXPECT_EQ(pp_pragma_import, Directives[15].Kind);
+ EXPECT_EQ(pp_pragma_push_macro, Directives[16].Kind);
+ EXPECT_EQ(pp_pragma_pop_macro, Directives[17].Kind);
+ EXPECT_EQ(pp_pragma_include_alias, Directives[18].Kind);
+ EXPECT_EQ(cxx_export_module_decl, Directives[19].Kind);
+ EXPECT_EQ(cxx_import_decl, Directives[20].Kind);
+ EXPECT_EQ(pp_pragma_system_header, Directives[21].Kind);
+ EXPECT_EQ(pp_eof, Directives[22].Kind);
+}
+
TEST(MinimizeSourceToDependencyDirectivesTest, PoundWarningAndError) {
SmallVector<char, 128> Out;
More information about the cfe-commits
mailing list