mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-25 00:02:40 +01:00
Allow AAST to extract string literal values from HEREDOCs
Summary: Ref T13577. I'd like to `arc lint --everything` to find other bad calls to `pht()` and similar functions, but `n_HEREDOC` nodes currently can not generate a response to "getStringLiteralValue()". Support literal extraction from heredocs. Test Plan: Added a test, made it pass. Will lint everything. Maniphest Tasks: T13577 Differential Revision: https://secure.phabricator.com/D21455
This commit is contained in:
parent
1c327208d7
commit
83e63aeb07
2 changed files with 49 additions and 16 deletions
|
@ -14,6 +14,16 @@ foobar(null, null, '%s');
|
|||
|
||||
pht('x %s y');
|
||||
pht('x %s y'.'z');
|
||||
|
||||
pht(<<<HEREDOC
|
||||
a b c
|
||||
HEREDOC
|
||||
);
|
||||
|
||||
pht(<<<HEREDOC
|
||||
a %s c
|
||||
HEREDOC
|
||||
);
|
||||
~~~~~~~~~~
|
||||
error:3:1:XHP54:Formatted String
|
||||
error:7:1:XHP54:Formatted String
|
||||
|
@ -22,6 +32,7 @@ error:11:1:XHP54:Formatted String
|
|||
error:13:1:XHP54:Formatted String
|
||||
error:15:1:XHP54:Formatted String
|
||||
error:16:1:XHP54:Formatted String
|
||||
error:23:1:XHP54:Formatted String
|
||||
~~~~~~~~~~
|
||||
~~~~~~~~~~
|
||||
{
|
||||
|
|
|
@ -33,7 +33,9 @@ final class XHPASTNode extends AASTNode {
|
|||
return $this->getChildByIndex(0)->evalStatic();
|
||||
break;
|
||||
case 'n_STRING_SCALAR':
|
||||
return (string)$this->getStringLiteralValue();
|
||||
return phutil_string_cast($this->getStringLiteralValue());
|
||||
case 'n_HEREDOC':
|
||||
return phutil_string_cast($this->getStringLiteralValue());
|
||||
case 'n_NUMERIC_SCALAR':
|
||||
$value = $this->getSemanticString();
|
||||
if (preg_match('/^0x/i', $value)) {
|
||||
|
@ -186,31 +188,51 @@ final class XHPASTNode extends AASTNode {
|
|||
}
|
||||
|
||||
public function getStringLiteralValue() {
|
||||
if ($this->getTypeName() != 'n_STRING_SCALAR') {
|
||||
return null;
|
||||
$type_name = $this->getTypeName();
|
||||
|
||||
if ($type_name === 'n_HEREDOC') {
|
||||
$value = $this->getSemanticString();
|
||||
$value = phutil_split_lines($value);
|
||||
$value = array_slice($value, 1, -1);
|
||||
$value = implode('', $value);
|
||||
|
||||
// Strip the final newline from value, this isn't part of the string
|
||||
// literal.
|
||||
$value = preg_replace('/(\r|\n|\r\n)\z/', '', $value);
|
||||
|
||||
return $this->newStringLiteralFromSemanticString($value);
|
||||
}
|
||||
|
||||
$value = $this->getSemanticString();
|
||||
$type = $value[0];
|
||||
$value = preg_replace('/^b?[\'"]|[\'"]$/i', '', $value);
|
||||
$esc = false;
|
||||
$len = strlen($value);
|
||||
$out = '';
|
||||
if ($type_name === 'n_STRING_SCALAR') {
|
||||
$value = $this->getSemanticString();
|
||||
$type = $value[0];
|
||||
$value = preg_replace('/^b?[\'"]|[\'"]$/i', '', $value);
|
||||
|
||||
if ($type == "'") {
|
||||
// Single quoted strings treat everything as a literal except "\\" and
|
||||
// "\'".
|
||||
return str_replace(
|
||||
array('\\\\', '\\\''),
|
||||
array('\\', "'"),
|
||||
$value);
|
||||
if ($type == "'") {
|
||||
// Single quoted strings treat everything as a literal except "\\" and
|
||||
// "\'".
|
||||
return str_replace(
|
||||
array('\\\\', '\\\''),
|
||||
array('\\', "'"),
|
||||
$value);
|
||||
}
|
||||
|
||||
return $this->newStringLiteralFromSemanticString($value);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function newStringLiteralFromSemanticString($value) {
|
||||
// Double quoted strings treat "\X" as a literal if X isn't specifically
|
||||
// a character which needs to be escaped -- e.g., "\q" and "\'" are
|
||||
// literally "\q" and "\'". stripcslashes() is too aggressive, so find
|
||||
// all these under-escaped backslashes and escape them.
|
||||
|
||||
$len = strlen($value);
|
||||
$esc = false;
|
||||
$out = '';
|
||||
|
||||
for ($ii = 0; $ii < $len; $ii++) {
|
||||
$c = $value[$ii];
|
||||
if ($esc) {
|
||||
|
|
Loading…
Reference in a new issue