summaryrefslogtreecommitdiffstats
path: root/qmake
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@theqtcompany.com>2015-12-08 14:50:45 +0100
committerEdward Welbourne <edward.welbourne@theqtcompany.com>2015-12-15 16:40:08 +0000
commit5e7492325a745908e11403b1f729a840c180fc6c (patch)
tree9426ea1e3b60c015a0af74e6f2ab52a38c966c92 /qmake
parent209a26c6c4187a15cc6297000ad729392aac6454 (diff)
qmake: teach moc-detector to handle C++-11 raw strings
As for the #include-parser, the moc-detector's minimal C preprocessor could be confused by a raw string into ignoring large chunks of code. Change-Id: Id688e9a1f04628ce75a51a7d15269078c734288e Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'qmake')
-rw-r--r--qmake/generators/makefiledeps.cpp166
1 files changed, 85 insertions, 81 deletions
diff --git a/qmake/generators/makefiledeps.cpp b/qmake/generators/makefiledeps.cpp
index 53e0954749..635a775cb3 100644
--- a/qmake/generators/makefiledeps.cpp
+++ b/qmake/generators/makefiledeps.cpp
@@ -422,6 +422,87 @@ static bool matchWhileUnsplitting(const char *buffer, int buffer_len, int start,
return true;
}
+/* Advance from an opening quote at buffer[offset] to the matching close quote. */
+static int scanPastString(char *buffer, int buffer_len, int offset, int *lines)
+{
+ // It might be a C++11 raw string.
+ bool israw = false;
+ if (buffer[offset] == '"' && offset > 0) {
+ int explore = offset - 1;
+ while (explore > 0 && buffer[explore] != 'R') {
+ if (buffer[explore] == '8' || buffer[explore] == 'u' || buffer[explore] == 'U') {
+ explore--;
+ } else if (explore > 1 && qmake_endOfLine(buffer[explore])
+ && buffer[explore - 1] == '\\') {
+ explore -= 2;
+ } else if (explore > 2 && buffer[explore] == '\n'
+ && buffer[explore - 1] == '\r'
+ && buffer[explore - 2] == '\\') {
+ explore -= 3;
+ } else {
+ break;
+ }
+ }
+ israw = (buffer[explore] == 'R');
+ }
+
+ if (israw) {
+#define SKIP_BSNL(pos) skipEscapedLineEnds(buffer, buffer_len, (pos), lines)
+
+ offset = SKIP_BSNL(offset + 1);
+ const char *const delim = buffer + offset;
+ int clean = offset;
+ while (offset < buffer_len && buffer[offset] != '(') {
+ if (clean < offset)
+ buffer[clean++] = buffer[offset];
+ else
+ clean++;
+
+ offset = SKIP_BSNL(offset + 1);
+ }
+ /*
+ Not checking correctness (trust real compiler to do that):
+ - no controls, spaces, '(', ')', '\\' or (presumably) '"' in delim;
+ - at most 16 bytes in delim
+
+ Raw strings are surely defined after phase 2, when BSNLs are resolved;
+ so the delimiter's exclusion of '\\' and space (including newlines)
+ applies too late to save us the need to cope with BSNLs in it.
+ */
+
+ const int delimlen = buffer + clean - delim;
+ int matchlen = delimlen, extralines = 0;
+ while ((offset = SKIP_BSNL(offset + 1)) < buffer_len
+ && (buffer[offset] != ')'
+ || (delimlen > 0 &&
+ !matchWhileUnsplitting(buffer, buffer_len,
+ offset + 1, delim, delimlen,
+ &matchlen, &extralines))
+ || buffer[offset + 1 + matchlen] != '"')) {
+ // skip, but keep track of lines
+ if (qmake_endOfLine(buffer[offset]))
+ ++*lines;
+ extralines = 0;
+ }
+ *lines += extralines; // from the match
+ // buffer[offset] is ')'
+ offset += 1 + matchlen; // 1 for ')', then delim
+ // buffer[offset] is '"'
+
+#undef SKIP_BSNL
+ } else { // Traditional string or char literal:
+ const char term = buffer[offset];
+ while (++offset < buffer_len && buffer[offset] != term) {
+ if (buffer[offset] == '\\')
+ ++offset;
+ else if (qmake_endOfLine(buffer[offset]))
+ ++*lines;
+ }
+ }
+
+ return offset;
+}
+
bool QMakeSourceFileInfo::findDeps(SourceFile *file)
{
if(file->dep_checked || file->type == TYPE_UNKNOWN)
@@ -696,75 +777,7 @@ bool QMakeSourceFileInfo::findDeps(SourceFile *file)
case InCode:
// matching quotes (string literals and character literals)
if (buffer[x] == '\'' || buffer[x] == '"') {
- // It might be a C++11 raw string.
- bool israw = false;
- if (buffer[x] == '"' && x > 0) {
- int y = x - 1;
- while (y > 0 && buffer[y] != 'R') {
- if (buffer[y] == '8' || buffer[y] == 'u' || buffer[y] == 'U')
- y--;
- else if (y > 1 && qmake_endOfLine(buffer[y])
- && buffer[y - 1] == '\\')
- y -= 2;
- else if (y > 2 && buffer[y] == '\n'
- && buffer[y - 1] == '\r'
- && buffer[y - 2] == '\\')
- y -= 3;
- else
- break;
- }
- israw = (buffer[y] == 'R');
- }
- if (israw) {
- x = SKIP_BSNL(x + 1);
- const char *const delim = buffer + x;
- int clean = x;
- while (x < buffer_len && buffer[x] != '(') {
- if (clean < x)
- buffer[clean++] = buffer[x];
- else
- clean++;
-
- x = SKIP_BSNL(x + 1);
- }
- /*
- Not checking correctness (trust real compiler to do that):
- - no controls, spaces, '(', ')', '\\' or (presumably) '"' in delim;
- - at most 16 bytes in delim
-
- Raw strings are surely defined after phase 2, when
- BSNLs are resolved; so the delimiter's exclusion
- of '\\' and space (including newlines) applies too
- late to save us the need to cope with BSNLs in it.
- */
-
- const int delimlen = buffer + clean - delim;
- int matchlen = delimlen, extralines = 0;
- while ((x = SKIP_BSNL(x + 1)) < buffer_len
- && (buffer[x] != ')'
- || (delimlen > 0 &&
- !matchWhileUnsplitting(buffer, buffer_len,
- x + 1, delim, delimlen,
- &matchlen, &extralines))
- || buffer[x + 1 + matchlen] != '"')) {
- // skip, but keep track of lines
- if (qmake_endOfLine(buffer[x]))
- ++line_count;
- extralines = 0;
- }
- line_count += extralines; // from the match
- // buffer[x] is ')'
- x += 1 + matchlen; // 1 for ')', then delim
- // buffer[x] is '"'
- } else {
- const char term = buffer[x];
- while (++x < buffer_len && buffer[x] != term) {
- if (buffer[x] == '\\')
- ++x;
- else if (qmake_endOfLine(buffer[x]))
- ++line_count;
- }
- }
+ x = scanPastString(buffer, buffer_len, x, &line_count);
// for loop's ++x shall step over the closing quote.
}
// else: buffer[x] is just some code; move on.
@@ -924,19 +937,10 @@ bool QMakeSourceFileInfo::findMocs(SourceFile *file)
}
}
} else if (buffer[x] == '\'' || buffer[x] == '"') {
- const char term = buffer[x++];
- while(x < buffer_len) {
- if (buffer[x] == term)
- break;
- if (buffer[x] == '\\') {
- x+=2;
- } else {
- if (qmake_endOfLine(buffer[x]))
- ++line_count;
- ++x;
- }
- }
+ x = scanPastString(buffer, buffer_len, x, &line_count);
+ // Leaves us on closing quote; for loop's x++ steps us past it.
}
+
if (Option::debug_level && qmake_endOfLine(buffer[x]))
++line_count;
if (buffer_len > x + 2 && buffer[x + 1] == 'Q' &&