Skip to content

Commit

Permalink
Merge pull request #9916 from kkmuffme/slightly-improve-preg-performance
Browse files Browse the repository at this point in the history
docblock parser minor performance gain
  • Loading branch information
orklah committed Jun 15, 2023
2 parents 49c6f31 + 16aaa3a commit 70795bc
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/Psalm/Internal/Analyzer/CommentAnalyzer.php
Expand Up @@ -259,7 +259,7 @@ private static function decorateVarDocblockComment(
public static function sanitizeDocblockType(string $docblock_type): string
{
$docblock_type = preg_replace('@^[ \t]*\*@m', '', $docblock_type);
$docblock_type = preg_replace('/,\n\s+\}/', '}', $docblock_type);
$docblock_type = preg_replace('/,\n\s+}/', '}', $docblock_type);
return str_replace("\n", '', $docblock_type);
}

Expand Down Expand Up @@ -377,7 +377,7 @@ public static function splitDocLine(string $return_block): array
$remaining = trim(preg_replace('@^[ \t]*\* *@m', ' ', substr($return_block, $i + 1)));

if ($remaining) {
return array_merge([rtrim($type)], preg_split('/[ \s]+/', $remaining) ?: []);
return array_merge([rtrim($type)], preg_split('/\s+/', $remaining) ?: []);
}

return [$type];
Expand Down
41 changes: 24 additions & 17 deletions src/Psalm/Internal/Scanner/DocblockParser.php
Expand Up @@ -12,6 +12,7 @@
use function explode;
use function implode;
use function is_string;
use function ltrim;
use function min;
use function preg_match;
use function preg_replace;
Expand Down Expand Up @@ -54,17 +55,18 @@ public static function parse(string $docblock, int $offsetStart): ParsedDocblock
}

// Normalize multi-line @specials.
$lines = explode("\n", $docblock);
$lines = explode("\n", str_replace("\t", ' ', $docblock));
$has_r = strpos($docblock, "\r") === false ? false : true;

$special = [];

$first_line_padding = null;

$last = false;
foreach ($lines as $k => $line) {
if (preg_match('/^[ \t]*\*?\s*@\w/i', $line)) {
if (strpos($line, '@') !== false && preg_match('/^ *\*?\s*@\w/', $line)) {
$last = $k;
} elseif (preg_match('/^\s*\r?$/', $line)) {
} elseif (trim($line) === '') {
$last = false;
} elseif ($last !== false) {
$old_last_line = $lines[$last];
Expand All @@ -78,26 +80,29 @@ public static function parse(string $docblock, int $offsetStart): ParsedDocblock

foreach ($lines as $k => $line) {
$original_line_length = strlen($line);

$line = str_replace("\r", '', $line);
if ($has_r === true) {
$line = str_replace("\r", '', $line);
}

if ($first_line_padding === null) {
$asterisk_pos = strpos($line, '*');

if ($asterisk_pos) {
if ($asterisk_pos === 0 || $asterisk_pos === 1) {
$first_line_padding = '';
} elseif ($asterisk_pos > 1) {
$first_line_padding = substr($line, 0, $asterisk_pos - 1);
}
}

if (preg_match('/^[ \t]*\*?\s*@([\w\-\\\:]+)[\t ]*(.*)$/sm', $line, $matches, PREG_OFFSET_CAPTURE)) {
if (preg_match('/^ *\*?\s*@([\w\-\\\:]+) *(.*)$/sm', $line, $matches, PREG_OFFSET_CAPTURE)) {
/** @var array<int, array{string, int}> $matches */
[, $type_info, $data_info] = $matches;

[$type] = $type_info;
[$data, $data_offset] = $data_info;

if (strpos($data, '*')) {
$data = rtrim(preg_replace('/^[ \t]*\*\s*$/m', '', $data));
if (strpos($data, '*') !== false) {
$data = rtrim(preg_replace('/^ *\*\s*$/m', '', $data));
}

if (empty($special[$type])) {
Expand All @@ -111,24 +116,30 @@ public static function parse(string $docblock, int $offsetStart): ParsedDocblock
unset($lines[$k]);
} else {
// Strip the leading *, if present.
$text = $lines[$k];
$text = str_replace("\t", ' ', $text);
$text = preg_replace('/^ *\*/', '', $text, 1);
$lines[$k] = $text;
// technically only need to preg_replace('/^ *\*/', '', $lines[$k], 1)
// however it's slower and removing all spaces and * is fine
$lines[$k] = ltrim($lines[$k], ' *');
}

$line_offset += $original_line_length + 1;
}

// Smush the whole docblock to the left edge.
$min_indent = 80;
$reached_first_non_empty_line = false;
foreach ($lines as $k => $line) {
$indent = strspn($line, ' ');
if ($indent === strlen($line)) {
// This line consists of only spaces. Trim it completely.
if ($reached_first_non_empty_line === false) {
// remove any leading empty lines here, to avoid a preg_replace later
unset($lines[$k]);
continue;
}
$lines[$k] = '';
continue;
}
$reached_first_non_empty_line = true;
$min_indent = min($indent, $min_indent);
}
if ($min_indent > 0) {
Expand All @@ -142,10 +153,6 @@ public static function parse(string $docblock, int $offsetStart): ParsedDocblock
$docblock = implode("\n", $lines);
$docblock = rtrim($docblock);

// Trim any empty lines off the front, but leave the indent level if there
// is one.
$docblock = preg_replace('/^\s*\n/', '', $docblock, 1);

$parsed = new ParsedDocblock($docblock, $special, $first_line_padding ?: '');

self::resolveTags($parsed);
Expand Down
2 changes: 1 addition & 1 deletion tests/TypeReconciliation/ConditionalTest.php
Expand Up @@ -2433,7 +2433,7 @@ function splitDocLine($return_block)
if ($remaining) {
/** @var array<string> */
return array_merge([rtrim($type)], preg_split(\'/[ \s]+/\', $remaining));
return array_merge([rtrim($type)], preg_split(\'/\s+/\', $remaining));
}
return [$type];
Expand Down

0 comments on commit 70795bc

Please sign in to comment.