Skip to content

Commit 7fb48d6

Browse files
authored
Merge pull request #1040 from PHPCSStandards/feature/generic-unnecessaryheredoc-bug-fix-x2
Generic/UnnecessaryHeredoc: 2 bug fixes involving escape sequences
2 parents 512dc68 + 6457a5a commit 7fb48d6

File tree

5 files changed

+110
-6
lines changed

5 files changed

+110
-6
lines changed

src/Standards/Generic/Sniffs/Strings/UnnecessaryHeredocSniff.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,35 @@
1515
class UnnecessaryHeredocSniff implements Sniff
1616
{
1717

18+
/**
19+
* Escape chars which are supported in heredocs, but not in nowdocs.
20+
*
21+
* @var array<string>
22+
*/
23+
private $escapeChars = [
24+
// Octal sequences.
25+
'\0',
26+
'\1',
27+
'\2',
28+
'\3',
29+
'\4',
30+
'\5',
31+
'\6',
32+
'\7',
33+
34+
// Various whitespace and the escape char.
35+
'\n',
36+
'\r',
37+
'\t',
38+
'\v',
39+
'\e',
40+
'\f',
41+
42+
// Hex and unicode sequences.
43+
'\x',
44+
'\u',
45+
];
46+
1847

1948
/**
2049
* Returns an array of tokens this test wants to listen for.
@@ -81,14 +110,33 @@ public function process(File $phpcsFile, $stackPtr)
81110

82111
$phpcsFile->recordMetric($stackPtr, 'Heredoc contains interpolation or expression', 'no');
83112

113+
// Check for escape sequences which aren't supported in nowdocs.
114+
foreach ($this->escapeChars as $testChar) {
115+
if (strpos($body, $testChar) !== false) {
116+
return;
117+
}
118+
}
119+
84120
$warning = 'Detected heredoc without interpolation or expressions. Use nowdoc syntax instead';
85121

86122
$fix = $phpcsFile->addFixableWarning($warning, $stackPtr, 'Found');
87123
if ($fix === true) {
124+
$phpcsFile->fixer->beginChangeset();
125+
88126
$identifier = trim(ltrim($tokens[$stackPtr]['content'], '<'));
89127
$replaceWith = "'".trim($identifier, '"')."'";
90128
$replacement = str_replace($identifier, $replaceWith, $tokens[$stackPtr]['content']);
91129
$phpcsFile->fixer->replaceToken($stackPtr, $replacement);
130+
131+
for ($i = ($stackPtr + 1); $i < $closer; $i++) {
132+
$content = $tokens[$i]['content'];
133+
$content = str_replace(['\\$', '\\\\'], ['$', '\\'], $content);
134+
if ($tokens[$i]['content'] !== $content) {
135+
$phpcsFile->fixer->replaceToken($i, $content);
136+
}
137+
}
138+
139+
$phpcsFile->fixer->endChangeset();
92140
}
93141

94142
}//end process()

src/Standards/Generic/Tests/Strings/UnnecessaryHeredocUnitTest.1.inc

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,19 @@ END;
104104
$heredoc = <<< "END"
105105
some text
106106
some \$text
107-
some text
107+
some text \\ including a backslash
108108
END;
109+
110+
$heredoc = <<<EOD
111+
<?php
112+
echo 'The below line contains escape characters and should be recognized as needing heredoc';
113+
echo "aa\xC3\xC3 \xC3\xB8aa";
114+
EOD;
115+
116+
echo <<<EOT
117+
This should print a capital 'A': \x41
118+
EOT;
119+
120+
echo <<<EOT
121+
Here we should have a tab and 2 'A's: \t \101 \u{41}
122+
EOT;

src/Standards/Generic/Tests/Strings/UnnecessaryHeredocUnitTest.1.inc.fixed

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,20 @@ END;
103103

104104
$heredoc = <<< 'END'
105105
some text
106-
some \$text
107-
some text
106+
some $text
107+
some text \ including a backslash
108108
END;
109+
110+
$heredoc = <<<EOD
111+
<?php
112+
echo 'The below line contains escape characters and should be recognized as needing heredoc';
113+
echo "aa\xC3\xC3 \xC3\xB8aa";
114+
EOD;
115+
116+
echo <<<EOT
117+
This should print a capital 'A': \x41
118+
EOT;
119+
120+
echo <<<EOT
121+
Here we should have a tab and 2 'A's: \t \101 \u{41}
122+
EOT;

src/Standards/Generic/Tests/Strings/UnnecessaryHeredocUnitTest.2.inc

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,19 @@ $heredoc = <<<END
104104
$heredoc = <<< "END"
105105
some text
106106
some \$text
107-
some text
107+
some text \\ including a backslash
108108
END;
109+
110+
$heredoc = <<<EOD
111+
<?php
112+
echo 'The below line contains escape characters and should be recognized as needing heredoc';
113+
echo "aa\xC3\xC3 \xC3\xB8aa";
114+
EOD;
115+
116+
echo <<<EOT
117+
This should print a capital 'A': \x41
118+
EOT;
119+
120+
echo <<<EOT
121+
Here we should have a tab and 2 'A's: \t \101 \u{41}
122+
EOT;

src/Standards/Generic/Tests/Strings/UnnecessaryHeredocUnitTest.2.inc.fixed

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,20 @@ $heredoc = <<<'END'
103103

104104
$heredoc = <<< 'END'
105105
some text
106-
some \$text
107-
some text
106+
some $text
107+
some text \ including a backslash
108108
END;
109+
110+
$heredoc = <<<EOD
111+
<?php
112+
echo 'The below line contains escape characters and should be recognized as needing heredoc';
113+
echo "aa\xC3\xC3 \xC3\xB8aa";
114+
EOD;
115+
116+
echo <<<EOT
117+
This should print a capital 'A': \x41
118+
EOT;
119+
120+
echo <<<EOT
121+
Here we should have a tab and 2 'A's: \t \101 \u{41}
122+
EOT;

0 commit comments

Comments
 (0)