Skip to content

Commit a13f0da

Browse files
committedOct 8, 2019
[clang-scan-deps] Improve string/character literal skipping
The existing string/character literal skipping code in the dependency directives source minimizer has two issues: - It doesn't stop the scanning when a newline is reached before the terminating character, unlike the lexer which considers the token to be done (even if it's invalid) at the end of the line. - It doesn't support whitespace between '\' and the newline when looking if the '\' is used as a line continuation character. This commit fixes both issues. Differential Revision: https://reviews.llvm.org/D68436 llvm-svn: 374127
1 parent 143f6b8 commit a13f0da

File tree

2 files changed

+73
-11
lines changed

2 files changed

+73
-11
lines changed
 

‎clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,6 @@ static void skipRawString(const char *&First, const char *const End) {
185185
}
186186
}
187187

188-
static void skipString(const char *&First, const char *const End) {
189-
assert(*First == '\'' || *First == '"' || *First == '<');
190-
const char Terminator = *First == '<' ? '>' : *First;
191-
for (++First; First != End && *First != Terminator; ++First)
192-
if (*First == '\\')
193-
if (++First == End)
194-
return;
195-
if (First != End)
196-
++First; // Finish off the string.
197-
}
198-
199188
// Returns the length of EOL, either 0 (no end-of-line), 1 (\n) or 2 (\r\n)
200189
static unsigned isEOL(const char *First, const char *const End) {
201190
if (First == End)
@@ -206,6 +195,35 @@ static unsigned isEOL(const char *First, const char *const End) {
206195
return !!isVerticalWhitespace(First[0]);
207196
}
208197

198+
static void skipString(const char *&First, const char *const End) {
199+
assert(*First == '\'' || *First == '"' || *First == '<');
200+
const char Terminator = *First == '<' ? '>' : *First;
201+
for (++First; First != End && *First != Terminator; ++First) {
202+
// String and character literals don't extend past the end of the line.
203+
if (isVerticalWhitespace(*First))
204+
return;
205+
if (*First != '\\')
206+
continue;
207+
// Skip past backslash to the next character. This ensures that the
208+
// character right after it is skipped as well, which matters if it's
209+
// the terminator.
210+
if (++First == End)
211+
return;
212+
if (!isWhitespace(*First))
213+
continue;
214+
// Whitespace after the backslash might indicate a line continuation.
215+
const char *FirstAfterBackslashPastSpace = First;
216+
skipOverSpaces(FirstAfterBackslashPastSpace, End);
217+
if (unsigned NLSize = isEOL(FirstAfterBackslashPastSpace, End)) {
218+
// Advance the character pointer to the next line for the next
219+
// iteration.
220+
First = FirstAfterBackslashPastSpace + NLSize - 1;
221+
}
222+
}
223+
if (First != End)
224+
++First; // Finish off the string.
225+
}
226+
209227
// Returns the length of the skipped newline
210228
static unsigned skipNewline(const char *&First, const char *End) {
211229
if (First == End)

‎clang/unittests/Lex/DependencyDirectivesSourceMinimizerTest.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,50 @@ TEST(MinimizeSourceToDependencyDirectivesTest, PragmaOnce) {
594594
EXPECT_STREQ("#pragma once\n#include <test.h>\n", Out.data());
595595
}
596596

597+
TEST(MinimizeSourceToDependencyDirectivesTest,
598+
SkipLineStringCharLiteralsUntilNewline) {
599+
SmallVector<char, 128> Out;
600+
601+
StringRef Source = R"(#if NEVER_ENABLED
602+
#define why(fmt, ...) #error don't try me
603+
#endif
604+
605+
void foo();
606+
)";
607+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
608+
EXPECT_STREQ(
609+
"#if NEVER_ENABLED\n#define why(fmt,...) #error don't try me\n#endif\n",
610+
Out.data());
611+
612+
Source = R"(#if NEVER_ENABLED
613+
#define why(fmt, ...) "quote dropped
614+
#endif
615+
616+
void foo();
617+
)";
618+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
619+
EXPECT_STREQ(
620+
"#if NEVER_ENABLED\n#define why(fmt,...) \"quote dropped\n#endif\n",
621+
Out.data());
622+
}
623+
624+
TEST(MinimizeSourceToDependencyDirectivesTest,
625+
SupportWhitespaceBeforeLineContinuationInStringSkipping) {
626+
SmallVector<char, 128> Out;
627+
628+
StringRef Source = "#define X '\\ \t\nx'\nvoid foo() {}";
629+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
630+
EXPECT_STREQ("#define X '\\ \t\nx'\n", Out.data());
631+
632+
Source = "#define X \"\\ \r\nx\"\nvoid foo() {}";
633+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
634+
EXPECT_STREQ("#define X \"\\ \r\nx\"\n", Out.data());
635+
636+
Source = "#define X \"\\ \r\nx\n#include <x>\n";
637+
ASSERT_FALSE(minimizeSourceToDependencyDirectives(Source, Out));
638+
EXPECT_STREQ("#define X \"\\ \r\nx\n#include <x>\n", Out.data());
639+
}
640+
597641
TEST(MinimizeSourceToDependencyDirectivesTest, CxxModules) {
598642
SmallVector<char, 128> Out;
599643
SmallVector<Token, 4> Tokens;

0 commit comments

Comments
 (0)
Please sign in to comment.