Merge branch '3.4' into 4.3

* 3.4:
  [Config][ReflectionClassResource] Handle parameters with undefined constant as their default values
  fix dumping number-like string parameters
  [Console] Fix autocomplete multibyte input support
  [Config] don't break on virtual stack frames in ClassExistenceResource
This commit is contained in:
Nicolas Grekas 2019-11-29 18:37:27 +01:00
commit 73ea89b4c2
10 changed files with 127 additions and 18 deletions

View File

@ -183,15 +183,17 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
}
$props = [
'file' => $trace[$i]['file'],
'line' => $trace[$i]['line'],
'file' => isset($trace[$i]['file']) ? $trace[$i]['file'] : null,
'line' => isset($trace[$i]['line']) ? $trace[$i]['line'] : null,
'trace' => \array_slice($trace, 1 + $i),
];
foreach ($props as $p => $v) {
$r = new \ReflectionProperty('Exception', $p);
$r->setAccessible(true);
$r->setValue($e, $v);
if (null !== $v) {
$r = new \ReflectionProperty('Exception', $p);
$r->setAccessible(true);
$r->setValue($e, $v);
}
}
}

View File

@ -141,12 +141,56 @@ class ReflectionClassResource implements SelfCheckingResourceInterface
}
foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) {
yield preg_replace('/^ @@.*/m', '', $m);
$defaults = [];
$parametersWithUndefinedConstants = [];
foreach ($m->getParameters() as $p) {
$defaults[$p->name] = $p->isDefaultValueAvailable() ? $p->getDefaultValue() : null;
if (!$p->isDefaultValueAvailable()) {
$defaults[$p->name] = null;
continue;
}
if (!$p->isDefaultValueConstant() || \defined($p->getDefaultValueConstantName())) {
$defaults[$p->name] = $p->getDefaultValue();
continue;
}
$defaults[$p->name] = $p->getDefaultValueConstantName();
$parametersWithUndefinedConstants[$p->name] = true;
}
if (!$parametersWithUndefinedConstants) {
yield preg_replace('/^ @@.*/m', '', $m);
} else {
$stack = [
$m->getDocComment(),
$m->getName(),
$m->isAbstract(),
$m->isFinal(),
$m->isStatic(),
$m->isPublic(),
$m->isPrivate(),
$m->isProtected(),
$m->returnsReference(),
$m->hasReturnType() ? $m->getReturnType()->getName() : '',
];
foreach ($m->getParameters() as $p) {
if (!isset($parametersWithUndefinedConstants[$p->name])) {
$stack[] = (string) $p;
} else {
$stack[] = $p->isOptional();
$stack[] = $p->hasType() ? $p->getType()->getName() : '';
$stack[] = $p->isPassedByReference();
$stack[] = $p->isVariadic();
$stack[] = $p->getName();
}
}
yield implode(',', $stack);
}
yield print_r($defaults, true);
}

View File

@ -64,8 +64,12 @@ class ReflectionClassResourceTest extends TestCase
/**
* @dataProvider provideHashedSignature
*/
public function testHashedSignature($changeExpected, $changedLine, $changedCode)
public function testHashedSignature($changeExpected, $changedLine, $changedCode, $setContext = null)
{
if ($setContext) {
$setContext();
}
$code = <<<'EOPHP'
/* 0*/
/* 1*/ class %s extends ErrorException
@ -83,7 +87,9 @@ class ReflectionClassResourceTest extends TestCase
/*13*/ protected function prot($a = []) {}
/*14*/
/*15*/ private function priv() {}
/*16*/ }
/*16*/
/*17*/ public function ccc($bar = A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC) {}
/*18*/ }
EOPHP;
static $expectedSignature, $generateSignature;
@ -98,7 +104,9 @@ EOPHP;
}
$code = explode("\n", $code);
$code[$changedLine] = $changedCode;
if (null !== $changedCode) {
$code[$changedLine] = $changedCode;
}
eval(sprintf(implode("\n", $code), $class = 'Foo'.str_replace('.', '_', uniqid('', true))));
$signature = implode("\n", iterator_to_array($generateSignature(new \ReflectionClass($class))));
@ -142,6 +150,10 @@ EOPHP;
yield [0, 7, 'protected int $prot;'];
yield [0, 9, 'private string $priv;'];
}
yield [1, 17, 'public function ccc($bar = 187) {}'];
yield [1, 17, 'public function ccc($bar = ANOTHER_ONE_THAT_WILL_NEVER_BE_DEFINED_CCCCCCCCC) {}'];
yield [1, 17, null, static function () { \define('A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC', 'foo'); }];
}
public function testEventSubscriber()

View File

@ -226,7 +226,7 @@ class QuestionHelper extends Helper
} elseif ("\177" === $c) { // Backspace Character
if (0 === $numMatches && 0 !== $i) {
--$i;
$fullChoice = substr($fullChoice, 0, -1);
$fullChoice = self::substr($fullChoice, 0, -1);
// Move cursor backwards
$output->write("\033[1D");
}
@ -240,7 +240,7 @@ class QuestionHelper extends Helper
}
// Pop the last character off the end of our string
$ret = substr($ret, 0, $i);
$ret = self::substr($ret, 0, $i);
} elseif ("\033" === $c) {
// Did we read an escape sequence?
$c .= fread($inputStream, 2);
@ -266,7 +266,7 @@ class QuestionHelper extends Helper
$remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice))));
$output->write($remainingCharacters);
$fullChoice .= $remainingCharacters;
$i = \strlen($fullChoice);
$i = self::strlen($fullChoice);
$matches = array_filter(
$autocomplete($ret),

View File

@ -175,19 +175,20 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
// Acm<NEWLINE>
// Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
// <NEWLINE>
// <UP ARROW><UP ARROW><NEWLINE>
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
// <UP ARROW><UP ARROW><UP ARROW><NEWLINE>
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
// <DOWN ARROW><NEWLINE>
// S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
// F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n");
// F⭐<TAB><BACKSPACE><BACKSPACE>⭐<TAB><NEWLINE>
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\nF⭐\t\177\177\t\n");
$dialog = new QuestionHelper();
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);
$question = new Question('Please select a bundle', 'FrameworkBundle');
$question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle']);
$question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle', 'F⭐Y']);
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('AsseticBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
@ -197,6 +198,7 @@ class QuestionHelperTest extends AbstractQuestionHelperTest
$this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('F⭐Y', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
}
public function testAskWithAutocompleteCallback()

View File

@ -324,6 +324,11 @@ class XmlDumper extends Dumper
if (\in_array($value, ['null', 'true', 'false'], true)) {
$element->setAttribute('type', 'string');
}
if (\is_string($value) && (is_numeric($value) || preg_match('/^0b[01]*$/', $value) || preg_match('/^0x[0-9a-f]++$/i', $value))) {
$element->setAttribute('type', 'string');
}
$text = $this->document->createTextNode(self::phpToXml($value));
$element->appendChild($text);
}

View File

@ -11,6 +11,17 @@ $container = new ContainerBuilder(new ParameterBag([
'values' => [true, false, null, 0, 1000.3, 'true', 'false', 'null'],
'binary' => "\xf0\xf0\xf0\xf0",
'binary-control-char' => "This is a Bell char \x07",
'null string' => 'null',
'string of digits' => '123',
'string of digits prefixed with minus character' => '-123',
'true string' => 'true',
'false string' => 'false',
'binary number string' => '0b0110',
'numeric string' => '-1.2E2',
'hexadecimal number string' => '0xFF',
'float string' => '10100.1',
'positive float string' => '+10100.1',
'negative float string' => '-10100.1',
]));
return $container;

View File

@ -126,6 +126,17 @@ class ProjectServiceContainer extends Container
],
'binary' => 'ðððð',
'binary-control-char' => 'This is a Bell char ',
'null string' => 'null',
'string of digits' => '123',
'string of digits prefixed with minus character' => '-123',
'true string' => 'true',
'false string' => 'false',
'binary number string' => '0b0110',
'numeric string' => '-1.2E2',
'hexadecimal number string' => '0xFF',
'float string' => '10100.1',
'positive float string' => '+10100.1',
'negative float string' => '-10100.1',
];
}
}

View File

@ -20,6 +20,17 @@
</parameter>
<parameter key="binary" type="binary">8PDw8A==</parameter>
<parameter key="binary-control-char" type="binary">VGhpcyBpcyBhIEJlbGwgY2hhciAH</parameter>
<parameter key="null string" type="string">null</parameter>
<parameter key="string of digits" type="string">123</parameter>
<parameter key="string of digits prefixed with minus character" type="string">-123</parameter>
<parameter key="true string" type="string">true</parameter>
<parameter key="false string" type="string">false</parameter>
<parameter key="binary number string" type="string">0b0110</parameter>
<parameter key="numeric string" type="string">-1.2E2</parameter>
<parameter key="hexadecimal number string" type="string">0xFF</parameter>
<parameter key="float string" type="string">10100.1</parameter>
<parameter key="positive float string" type="string">+10100.1</parameter>
<parameter key="negative float string" type="string">-10100.1</parameter>
</parameters>
<services>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" public="true" synthetic="true"/>

View File

@ -6,6 +6,17 @@ parameters:
values: [true, false, null, 0, 1000.3, 'true', 'false', 'null']
binary: !!binary 8PDw8A==
binary-control-char: !!binary VGhpcyBpcyBhIEJlbGwgY2hhciAH
null string: 'null'
string of digits: '123'
string of digits prefixed with minus character: '-123'
true string: 'true'
false string: 'false'
binary number string: '0b0110'
numeric string: '-1.2E2'
hexadecimal number string: '0xFF'
float string: '10100.1'
positive float string: '+10100.1'
negative float string: '-10100.1'
services:
service_container: