|
19 | 19 | import static com.google.errorprone.BugPattern.SeverityLevel.ERROR;
|
20 | 20 | import static com.google.errorprone.matchers.Description.NO_MATCH;
|
21 | 21 | import static com.google.errorprone.util.SourceVersion.supportsTextBlocks;
|
22 |
| -import static java.util.stream.Collectors.joining; |
23 | 22 |
|
24 | 23 | import com.google.errorprone.BugPattern;
|
25 | 24 | import com.google.errorprone.VisitorState;
|
@@ -56,32 +55,38 @@ public Description matchLiteral(LiteralTree tree, VisitorState state) {
|
56 | 55 | // Tokenize the source to make sure we omit comments. Desugaring of "a" + "b" into a single
|
57 | 56 | // string literal happens really early in compilation, and we want to ensure we don't match
|
58 | 57 | // on any "\s" in comments.
|
59 |
| - // This is quite ugly in that we end up with a string that looks like "foo""bar", i.e. |
60 |
| - // including the quotes, but that doesn't matter for this check. |
61 | 58 | var tokens = ErrorProneTokens.getTokens(source, state.context);
|
62 |
| - var literal = |
63 |
| - tokens.stream() |
64 |
| - .filter(t -> t.kind().equals(TokenKind.STRINGLITERAL)) |
65 |
| - .map(t -> source.substring(t.pos(), t.endPos())) |
66 |
| - .collect(joining()); |
67 |
| - boolean seenEscape = false; |
68 |
| - for (int i = 0; i < literal.length(); ++i) { |
69 |
| - switch (literal.charAt(i)) { |
70 |
| - case '\n': |
71 |
| - seenEscape = false; |
72 |
| - break; |
73 |
| - case '\\': |
74 |
| - i++; |
75 |
| - if (literal.charAt(i) == 's') { |
76 |
| - seenEscape = true; |
| 59 | + for (var token : tokens) { |
| 60 | + if (!token.kind().equals(TokenKind.STRINGLITERAL)) { |
| 61 | + continue; |
| 62 | + } |
| 63 | + var sourceWithQuotes = source.substring(token.pos(), token.endPos()); |
| 64 | + boolean isBlockLiteral = sourceWithQuotes.startsWith("\"\"\""); |
| 65 | + int quoteSize = isBlockLiteral ? 3 : 1; |
| 66 | + var literal = sourceWithQuotes.substring(quoteSize, sourceWithQuotes.length() - quoteSize); |
| 67 | + boolean seenEscape = false; |
| 68 | + for (int i = 0; i < literal.length(); ++i) { |
| 69 | + switch (literal.charAt(i)) { |
| 70 | + case '\n': |
| 71 | + seenEscape = false; |
| 72 | + break; |
| 73 | + case '\\': |
| 74 | + i++; |
| 75 | + if (literal.charAt(i) == 's') { |
| 76 | + seenEscape = true; |
| 77 | + break; |
| 78 | + } |
| 79 | + // fall through |
| 80 | + default: |
| 81 | + if (seenEscape) { |
| 82 | + return describeMatch(tree); |
| 83 | + } |
77 | 84 | break;
|
78 |
| - } |
79 |
| - // fall through |
80 |
| - default: |
81 |
| - if (seenEscape) { |
82 |
| - return describeMatch(tree); |
83 |
| - } |
84 |
| - break; |
| 85 | + } |
| 86 | + } |
| 87 | + // Catch _trailing_ \s at the end of non-block literals. |
| 88 | + if (seenEscape && !isBlockLiteral) { |
| 89 | + return describeMatch(tree); |
85 | 90 | }
|
86 | 91 | }
|
87 | 92 | }
|
|
0 commit comments